Mercurial > pidgin
annotate src/protocols/icq/tcplink.c @ 6629:bdc448cf4cb6
[gaim-migrate @ 7153]
Tim Ringenbach (marv_sf) writes:
" This patch makes sending colors in yahoo work. It also
makes a few changing to receiving them, and addresses
most of the problems with that patch (which I think
were all related to the fact it didn't do outgoing colors).
It now handles bold, italic, underline, font face, font
size, and font color in both directions. It disables
the background color button if the prpl is yahoo (in a
generic way), and farthermore strips out any <body>
tags that the user might try to type anyway (the yahoo
server purposely mangles them).
It also adds a line to g_strescape some debug messages
because I got tired them of changing the color of my
terminal.
I think I got all the bugs out. If you run with -d or
open the debug window, it will show you what both
conversion function returned, which should help track
down any problems."
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Tue, 26 Aug 2003 01:34:51 +0000 |
parents | f0a2a9afdb77 |
children |
rev | line source |
---|---|
2086 | 1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | |
3 /* | |
2496
f0a2a9afdb77
[gaim-migrate @ 2509]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
4 * $Id: tcplink.c 2509 2001-10-13 00:06:18Z warmenhoven $ |
2086 | 5 * |
6 * Copyright (C) 1998-2001, Denis V. Dmitrienko <denis@null.net> and | |
7 * Bill Soudan <soudan@kde.org> | |
8 * | |
9 * This program is free software; you can redistribute it and/or modify | |
10 * it under the terms of the GNU General Public License as published by | |
11 * the Free Software Foundation; either version 2 of the License, or | |
12 * (at your option) any later version. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 * GNU General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU General Public License | |
20 * along with this program; if not, write to the Free Software | |
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 * | |
23 */ | |
24 | |
25 #include <stdlib.h> | |
26 | |
27 #include <fcntl.h> | |
28 #include <errno.h> | |
29 | |
30 #ifdef _WIN32 | |
31 #include <winsock.h> | |
32 #define EINPROGRESS WSAEINPROGRESS | |
33 #define ENETUNREACH WSAENETUNREACH | |
34 #define ECONNREFUSED WSAECONNREFUSED | |
35 #define ETIMEDOUT WSAETIMEDOUT | |
36 #define EOPNOTSUPP WSAEOPNOTSUPP | |
37 #define EAFNOSUPPORT WSAEAFNOSUPPORT | |
38 #define EWOULDBLOCK WSAEWOULDBLOCK | |
39 #else | |
40 #include <netdb.h> | |
41 #endif | |
42 | |
43 #include "icqlib.h" | |
44 #include "stdpackets.h" | |
45 #include "tcp.h" | |
46 #include "errno.h" | |
47 #include "chatsession.h" | |
48 #include "filesession.h" | |
49 #include "contacts.h" | |
2496
f0a2a9afdb77
[gaim-migrate @ 2509]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
50 #include "socketmanager.h" |
2086 | 51 |
52 icq_TCPLink *icq_TCPLinkNew(icq_Link *icqlink) | |
53 { | |
54 icq_TCPLink *p=(icq_TCPLink *)malloc(sizeof(icq_TCPLink)); | |
55 | |
56 p->socket=-1; | |
57 p->icqlink=icqlink; | |
58 p->mode=0; | |
59 p->session=0L; | |
60 p->type=TCP_LINK_MESSAGE; | |
61 p->buffer_count=0; | |
62 p->send_queue=icq_ListNew(); | |
63 p->received_queue=icq_ListNew(); | |
64 p->id=0; | |
65 p->remote_uin=0; | |
66 p->remote_version=0; | |
67 p->flags=0; | |
68 p->proxy_status = 0; | |
69 p->connect_timeout = NULL; | |
70 | |
71 if(p) | |
72 icq_ListEnqueue(icqlink->d->icq_TCPLinks, p); | |
73 | |
74 return p; | |
75 } | |
76 | |
77 int _icq_TCPLinkDelete(void *pv, va_list data) | |
78 { | |
79 icq_Packet *p=(icq_Packet *)pv; | |
80 icq_Link *icqlink=va_arg(data, icq_Link *); | |
81 | |
82 /* notify the app the packet didn't make it */ | |
83 if(p->id) | |
84 invoke_callback(icqlink, icq_RequestNotify)(icqlink, p->id, | |
85 ICQ_NOTIFY_FAILED, 0, 0); | |
86 | |
87 return 0; | |
88 } | |
89 | |
90 void icq_TCPLinkDelete(void *pv) | |
91 { | |
92 icq_TCPLink *p=(icq_TCPLink *)pv; | |
93 | |
94 /* process anything left in the received queue */ | |
95 icq_TCPLinkProcessReceived(p); | |
96 | |
97 /* make sure we notify app that packets in send queue didn't make it */ | |
98 (void)icq_ListTraverse(p->send_queue, _icq_TCPLinkDelete, p->icqlink); | |
99 | |
100 /* destruct all packets still waiting on queues */ | |
101 icq_ListDelete(p->send_queue, icq_PacketDelete); | |
102 icq_ListDelete(p->received_queue, icq_PacketDelete); | |
103 | |
104 /* if this is a chat or file link, delete the associated session as | |
105 * well, but make sure we unassociate ourself first so the session | |
106 * doesn't try to close us */ | |
107 if(p->session) | |
108 { | |
109 if(p->type==TCP_LINK_CHAT) | |
110 { | |
111 icq_ChatSession *psession=p->session; | |
112 psession->tcplink=NULL; | |
113 icq_ChatSessionClose(psession); | |
114 } | |
115 | |
116 if(p->type==TCP_LINK_FILE) { | |
117 icq_FileSession *psession=p->session; | |
118 psession->tcplink=NULL; | |
119 icq_FileSessionClose(psession); | |
120 } | |
121 } | |
122 | |
123 /* close the socket after we notify app so app can read errno if necessary */ | |
124 if (p->socket > -1) | |
125 { | |
126 icq_SocketDelete(p->socket); | |
127 } | |
128 | |
129 if (p->connect_timeout) | |
130 { | |
131 icq_TimeoutDelete(p->connect_timeout); | |
132 } | |
133 | |
134 free(p); | |
135 } | |
136 | |
137 void icq_TCPLinkClose(icq_TCPLink *plink) | |
138 { | |
139 icq_ListRemove(plink->icqlink->d->icq_TCPLinks, plink); | |
140 icq_TCPLinkDelete(plink); | |
141 } | |
142 | |
143 int icq_TCPLinkProxyConnect(icq_TCPLink *plink, DWORD uin, int port) | |
144 { | |
145 struct sockaddr_in prsin; | |
146 struct hostent *host_struct; | |
147 int conct; | |
148 | |
149 (void)uin; (void)port; | |
150 | |
151 prsin.sin_addr.s_addr = htonl(plink->icqlink->icq_ProxyIP); | |
152 if(prsin.sin_addr.s_addr == (unsigned long)-1) | |
153 { | |
154 prsin.sin_addr.s_addr = inet_addr(plink->icqlink->icq_ProxyHost); | |
155 if(prsin.sin_addr.s_addr == (unsigned long)-1) /* name isn't n.n.n.n so must be DNS */ | |
156 { | |
157 host_struct = gethostbyname(plink->icqlink->icq_ProxyHost); | |
158 if(host_struct == 0L) | |
159 { | |
160 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Can't find hostname: %s\n", | |
161 plink->icqlink->icq_ProxyHost); | |
162 return -1; | |
163 } | |
164 prsin.sin_addr = *((struct in_addr *)host_struct->h_addr); | |
165 } | |
166 } | |
167 prsin.sin_family = AF_INET; /* we're using the inet not appletalk*/ | |
168 prsin.sin_port = htons(plink->icqlink->icq_ProxyPort); /* port */ | |
169 /* flags = fcntl(plink->socket, F_GETFL, 0); */ | |
170 /* fcntl(plink->socket, F_SETFL, flags & (~O_NONBLOCK)); */ | |
171 plink->mode |= TCP_LINK_SOCKS_CONNECTING; | |
172 conct = connect(plink->socket, (struct sockaddr *) &prsin, sizeof(prsin)); | |
173 if(conct == -1) /* did we connect ?*/ | |
174 { | |
175 if(errno != EINPROGRESS) | |
176 { | |
177 conct = errno; | |
178 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n"); | |
179 return conct; | |
180 } | |
181 return 1; | |
182 } | |
183 return 0; | |
184 } | |
185 | |
186 int icq_TCPLinkProxyRequestAuthorization(icq_TCPLink *plink) | |
187 { | |
188 char buf[1024]; | |
189 | |
190 int hasName = plink->icqlink->icq_ProxyName && | |
191 strlen(plink->icqlink->icq_ProxyName); | |
192 int hasPass = plink->icqlink->icq_ProxyPass && | |
193 strlen(plink->icqlink->icq_ProxyPass); | |
194 int authEnabled = hasName && hasPass && plink->icqlink->icq_ProxyAuth; | |
195 | |
196 plink->mode = (plink->mode & (~TCP_LINK_SOCKS_CONNECTING)); | |
197 buf[0] = 5; /* protocol version */ | |
198 buf[1] = 1; /* number of methods */ | |
199 buf[2] = authEnabled ? 2 : 0; /* authentication method */ | |
200 | |
201 plink->mode |= authEnabled ? TCP_LINK_SOCKS_AUTHORIZATION : | |
202 TCP_LINK_SOCKS_NOAUTHSTATUS; | |
203 | |
204 #ifdef _WIN32 | |
205 if(send(plink->socket, buf, 3, 0) != 3) | |
206 return errno; | |
207 #else | |
208 if(write(plink->socket, buf, 3) != 3) | |
209 return errno; | |
210 #endif | |
211 return 0; | |
212 } | |
213 | |
214 int icq_TCPLinkProxyAuthorization(icq_TCPLink *plink) | |
215 { | |
216 int res; | |
217 char buf[1024]; | |
218 | |
219 plink->mode &= ~TCP_LINK_SOCKS_AUTHORIZATION; | |
220 plink->mode |= TCP_LINK_SOCKS_AUTHSTATUS; | |
221 | |
222 #ifdef _WIN32 | |
223 res = recv(plink->socket, buf, 2, 0); | |
224 #else | |
225 res = read(plink->socket, buf, 2); | |
226 #endif | |
227 if(res != 2 || buf[0] != 5 || buf[1] != 2) /* username/password authentication*/ | |
228 { | |
229 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n"); | |
230 icq_SocketDelete(plink->socket); | |
231 return -1; | |
232 } | |
233 buf[0] = 1; /* version of subnegotiation */ | |
234 buf[1] = strlen(plink->icqlink->icq_ProxyName); | |
235 memcpy(&buf[2], plink->icqlink->icq_ProxyName, buf[1]); | |
236 buf[2+buf[1]] = strlen(plink->icqlink->icq_ProxyPass); | |
237 memcpy(&buf[3+buf[1]], plink->icqlink->icq_ProxyPass, buf[2+buf[1]]); | |
238 #ifdef _WIN32 | |
239 if(send(plink->socket, buf, buf[1]+buf[2+buf[1]]+3, 0) != buf[1] + buf[2+buf[1]]+3) | |
240 return errno; | |
241 #else | |
242 if(write(plink->socket, buf, buf[1]+buf[2+buf[1]]+3) != buf[1] + buf[2+buf[1]]+3) | |
243 return errno; | |
244 #endif | |
245 return 0; | |
246 } | |
247 | |
248 int icq_TCPLinkProxyAuthStatus(icq_TCPLink *plink) | |
249 { | |
250 int res; | |
251 char buf[20]; | |
252 | |
253 plink->mode = (plink->mode & (~TCP_LINK_SOCKS_AUTHSTATUS)) | TCP_LINK_SOCKS_CROSSCONNECT; | |
254 #ifdef _WIN32 | |
255 res = recv(plink->socket, buf, 2, 0); | |
256 #else | |
257 res = read(plink->socket, buf, 2); | |
258 #endif | |
259 if(res != 2 || buf[0] != 1 || buf[1] != 0) | |
260 { | |
261 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Authorization failure\n"); | |
262 icq_SocketDelete(plink->socket); | |
263 return -1; | |
264 } | |
265 return 0; | |
266 } | |
267 | |
268 int icq_TCPLinkProxyNoAuthStatus(icq_TCPLink *plink) | |
269 { | |
270 int res; | |
271 char buf[20]; | |
272 | |
273 plink->mode = (plink->mode & (~TCP_LINK_SOCKS_NOAUTHSTATUS)) | TCP_LINK_SOCKS_CROSSCONNECT; | |
274 #ifdef _WIN32 | |
275 res = recv(plink->socket, buf, 2, 0); | |
276 #else | |
277 res = read(plink->socket, buf, 2); | |
278 #endif | |
279 if(res != 2 || buf[0] != 5 || buf[1] != 0) /* no authentication required */ | |
280 { | |
281 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n"); | |
282 icq_SocketDelete(plink->socket); | |
283 return -1; | |
284 } | |
285 return 0; | |
286 } | |
287 | |
288 int icq_TCPLinkProxyCrossConnect(icq_TCPLink *plink) | |
289 { | |
290 char buf[20]; | |
291 | |
292 plink->mode = (plink->mode & ~(TCP_LINK_SOCKS_CROSSCONNECT)) | TCP_LINK_SOCKS_CONNSTATUS; | |
293 buf[0] = 5; /* protocol version */ | |
294 buf[1] = 1; /* command connect */ | |
295 buf[2] = 0; /* reserved */ | |
296 buf[3] = 1; /* address type IP v4 */ | |
297 memcpy(&buf[4], &plink->remote_address.sin_addr.s_addr, 4); | |
298 memcpy(&buf[8], &plink->remote_address.sin_port, 2); | |
299 #ifdef _WIN32 | |
300 if(send(plink->socket, buf, 10, 0) != 10) | |
301 return errno; | |
302 #else | |
303 if(write(plink->socket, buf, 10) != 10) | |
304 return errno; | |
305 #endif | |
306 return 0; | |
307 } | |
308 | |
309 int icq_TCPLinkProxyConnectStatus(icq_TCPLink *plink) | |
310 { | |
311 int res; | |
312 char buf[1024]; | |
313 | |
314 plink->mode = (plink->mode & (~TCP_LINK_SOCKS_CONNSTATUS)); | |
315 #ifdef _WIN32 | |
316 res = recv(plink->socket, buf, 10, 0); | |
317 #else | |
318 res = read(plink->socket, buf, 10); | |
319 #endif | |
320 if(res != 10 || buf[0] != 5 || buf[1] != 0) | |
321 { | |
322 switch(buf[1]) | |
323 { | |
324 case 1: | |
325 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] General SOCKS server failure\n"); | |
326 res = EFAULT; | |
327 break; | |
328 case 2: | |
329 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection not allowed by ruleset\n"); | |
330 res = EACCES; | |
331 break; | |
332 case 3: | |
333 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Network unreachable\n"); | |
334 res = ENETUNREACH; | |
335 break; | |
336 case 4: | |
337 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Host unreachable\n"); | |
338 res = ENETUNREACH; | |
339 break; | |
340 case 5: | |
341 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n"); | |
342 res = ECONNREFUSED; | |
343 break; | |
344 case 6: | |
345 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] TTL expired\n"); | |
346 res = ETIMEDOUT; | |
347 break; | |
348 case 7: | |
349 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Command not supported\n"); | |
350 res = EOPNOTSUPP; | |
351 break; | |
352 case 8: | |
353 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Address type not supported\n"); | |
354 res = EAFNOSUPPORT; | |
355 break; | |
356 default: | |
357 icq_FmtLog(plink->icqlink, ICQ_LOG_FATAL, "[SOCKS] Unknown SOCKS server failure\n"); | |
358 res = EFAULT; | |
359 break; | |
360 } | |
361 icq_SocketDelete(plink->socket); | |
362 return res; | |
363 } | |
364 return 0; | |
365 } | |
366 | |
367 int icq_TCPLinkConnect(icq_TCPLink *plink, DWORD uin, int port) | |
368 { | |
369 icq_ContactItem *pcontact=icq_ContactFind(plink->icqlink, uin); | |
370 icq_Packet *p; | |
371 int result; | |
372 | |
373 #ifndef _WIN32 | |
374 int flags; | |
375 #else | |
376 u_long iosflag; | |
377 #endif | |
378 | |
379 /* these return values never and nowhere checked */ | |
380 /* denis. */ | |
381 if(!pcontact) | |
382 return -2; | |
383 | |
384 if((plink->socket=icq_SocketNew(AF_INET, SOCK_STREAM, 0)) < 0) | |
385 return -3; | |
386 | |
387 /* bzero(&(plink->remote_address), sizeof(plink->remote_address)); Win32 incompatible... */ | |
388 memset(&(plink->remote_address), 0, sizeof(plink->remote_address)); | |
389 plink->remote_address.sin_family = AF_INET; | |
390 | |
391 /* if our IP is the same as the remote user's ip, connect to real_ip | |
392 instead since we're both probably behind a firewall */ | |
393 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
394 "local IP is %08X:%d, remote real IP is %08X:%d, remote IP is %08X:%d, port is %d\n", | |
395 plink->icqlink->icq_OurIP, | |
396 plink->icqlink->icq_OurPort, | |
397 pcontact->remote_real_ip, | |
398 pcontact->remote_port, | |
399 pcontact->remote_ip, | |
400 pcontact->remote_port, | |
401 port | |
402 ); | |
403 if (plink->icqlink->icq_OurIP == pcontact->remote_ip) | |
404 plink->remote_address.sin_addr.s_addr = htonl(pcontact->remote_real_ip); | |
405 else | |
406 plink->remote_address.sin_addr.s_addr = htonl(pcontact->remote_ip); | |
407 | |
408 if(plink->type==TCP_LINK_MESSAGE) | |
409 { | |
410 plink->remote_address.sin_port = htons(pcontact->remote_port); | |
411 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
412 "initiating message connect to %d (%s:%d)\n", uin, | |
413 inet_ntoa(*((struct in_addr *)(&(plink->remote_address.sin_addr)))), | |
414 pcontact->remote_port); | |
415 } | |
416 else | |
417 { | |
418 plink->remote_address.sin_port = htons(port); | |
419 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
420 "initiating file/chat connect to %d (%s:%d)\n", uin, | |
421 inet_ntoa(*((struct in_addr *)(&(plink->remote_address.sin_addr)))), | |
422 port); | |
423 } | |
424 | |
425 /* set the socket to non-blocking */ | |
426 #ifdef _WIN32 | |
427 iosflag = TRUE; | |
428 ioctlsocket(plink->socket, FIONBIO, &iosflag); | |
429 #else | |
430 flags=fcntl(plink->socket, F_GETFL, 0); | |
431 fcntl(plink->socket, F_SETFL, flags | O_NONBLOCK); | |
432 #endif | |
433 | |
434 if(!plink->icqlink->icq_UseProxy) | |
435 result=connect(plink->socket, (struct sockaddr *)&(plink->remote_address), | |
436 sizeof(plink->remote_address)); | |
437 else /* SOCKS proxy support */ | |
438 result=icq_TCPLinkProxyConnect(plink, uin, port); | |
439 /* FIXME: Here we should check for errors on connection */ | |
440 /* because of proxy support - it can't be checked */ | |
441 /* by getsockopt() later in _handle_ready_sockets() */ | |
442 /* denis. */ | |
443 | |
444 plink->mode|=TCP_LINK_MODE_CONNECTING; | |
445 | |
446 plink->remote_uin=uin; | |
447 | |
448 /* Send the hello packet */ | |
449 p=icq_TCPCreateInitPacket(plink); | |
450 icq_TCPLinkSend(plink, p); | |
451 | |
452 #ifdef TCP_PACKET_TRACE | |
453 printf("hello packet queued for %lu\n", uin); | |
454 #endif /* TCP_PACKET_TRACE */ | |
455 | |
456 icq_SocketSetHandler(plink->socket, ICQ_SOCKET_WRITE, | |
2496
f0a2a9afdb77
[gaim-migrate @ 2509]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
457 (icq_SocketHandler)icq_TCPLinkOnConnect, plink); |
2086 | 458 plink->connect_timeout=icq_TimeoutNew(TCP_LINK_CONNECT_TIMEOUT, |
459 (icq_TimeoutHandler)icq_TCPLinkClose, plink); | |
460 | |
461 return 1; | |
462 } | |
463 | |
464 icq_TCPLink *icq_TCPLinkAccept(icq_TCPLink *plink) | |
465 { | |
466 #ifdef _WIN32 | |
467 u_long iosflag; | |
468 #else | |
469 int flags; | |
470 #endif | |
471 int socket_fd; | |
472 size_t remote_length; | |
473 icq_TCPLink *pnewlink=icq_TCPLinkNew(plink->icqlink); | |
474 | |
475 if(pnewlink) | |
476 { | |
477 remote_length = sizeof(struct sockaddr_in); | |
478 socket_fd=icq_SocketAccept(plink->socket, | |
479 (struct sockaddr *)&(plink->remote_address), &remote_length); | |
480 | |
481 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
482 "accepting tcp connection from %s:%d\n", | |
483 inet_ntoa(*((struct in_addr *)(&(plink->remote_address.sin_addr)))), | |
484 ntohs(plink->remote_address.sin_port)); | |
485 | |
486 /* FIXME: make sure accept succeeded */ | |
487 | |
488 pnewlink->type=plink->type; | |
489 pnewlink->socket=socket_fd; | |
490 | |
491 /* first packet sent on an icq tcp link is always the hello packet */ | |
492 pnewlink->mode|=TCP_LINK_MODE_HELLOWAIT; | |
493 | |
494 /* install socket handler for new socket */ | |
495 icq_SocketSetHandler(socket_fd, ICQ_SOCKET_READ, | |
2496
f0a2a9afdb77
[gaim-migrate @ 2509]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
496 (icq_SocketHandler)icq_TCPLinkOnDataReceived, pnewlink); |
2086 | 497 } |
498 | |
499 /* set the socket to non-blocking */ | |
500 #ifdef _WIN32 | |
501 iosflag = TRUE; | |
502 ioctlsocket(pnewlink->socket, FIONBIO, &iosflag); | |
503 #else | |
504 flags=fcntl(pnewlink->socket, F_GETFL, 0); | |
505 fcntl(pnewlink->socket, F_SETFL, flags | O_NONBLOCK); | |
506 #endif | |
507 | |
508 return pnewlink; | |
509 } | |
510 | |
511 int icq_TCPLinkListen(icq_TCPLink *plink) | |
512 { | |
513 unsigned int t; | |
514 | |
515 /* listening links have 0 uin */ | |
516 plink->remote_uin=0; | |
517 | |
518 /* create tcp listen socket */ | |
519 if((plink->socket=icq_SocketNew(AF_INET, SOCK_STREAM, 0)) < 0) | |
520 return -1; | |
521 | |
522 /* must use memset, no bzero for Win32! */ | |
523 memset(&plink->socket_address, 0, sizeof(struct sockaddr_in)); | |
524 plink->socket_address.sin_family=AF_INET; | |
525 plink->socket_address.sin_addr.s_addr=htonl(INADDR_ANY); | |
526 plink->socket_address.sin_port=0; | |
527 | |
528 if(bind(plink->socket, (struct sockaddr *)&plink->socket_address, sizeof(struct sockaddr_in)) < 0) | |
529 return -2; | |
530 | |
531 if(listen(plink->socket, 5) < 0) | |
532 return -3; | |
533 | |
534 t=sizeof(struct sockaddr_in); | |
535 if(getsockname(plink->socket, (struct sockaddr *)&plink->socket_address, &t) < 0) | |
536 return -4; | |
537 | |
538 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
539 "created tcp listening socket %d, local address=%s:%d\n", | |
540 plink->socket, | |
541 inet_ntoa(*((struct in_addr *)(&plink->socket_address.sin_addr))), | |
542 ntohs(plink->socket_address.sin_port)); | |
543 | |
544 plink->mode|=TCP_LINK_MODE_LISTEN; | |
545 | |
2496
f0a2a9afdb77
[gaim-migrate @ 2509]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
546 icq_SocketSetHandler(plink->socket, ICQ_SOCKET_READ, (icq_SocketHandler)icq_TCPLinkAccept, |
2086 | 547 plink); |
548 | |
549 return 0; | |
550 } | |
551 | |
552 /* Doing Cyrillic translations for Chat dialog sessions */ | |
553 void icq_ChatRusConv_n(const char to[4], char *t_in, int t_len) | |
554 { | |
555 int i, j; | |
556 | |
557 for(i = j = 0; i < t_len; ++i) | |
558 { | |
559 if((((unsigned char)t_in[i]) < ' ') && (t_in[i] != '\r')) | |
560 { | |
561 if(i - 1 > j) | |
562 icq_RusConv_n(to, &t_in[j], i - j - 1); | |
563 switch(t_in[i]) | |
564 { | |
565 case '\x07': /* Bell */ | |
566 case '\x08': /* BackSpace */ | |
567 case '\x03': /* Chat is active */ | |
568 case '\x04': /* Chat is not active */ | |
569 break; | |
570 case '\x00': /* Foregroung color (RR GG BB ?? ) */ | |
571 case '\x01': /* Background color (RR GG BB ?? ) */ | |
572 case '\x11': /* Font style change (Bold - 1, Italic - 2, Underline - 4) */ | |
573 case '\x12': /* Font size change */ | |
574 i += 4; | |
575 break; | |
576 case '\x10': /* Font family and encoding change */ | |
577 i += t_in[i+1] + 2 + 2; | |
578 icq_RusConv_n(to, &t_in[i+3], t_in[i+1]); | |
579 break; | |
580 } | |
581 j = i + 1; | |
582 } | |
583 } | |
584 if(i > t_len) | |
585 i = t_len; | |
586 if(j > t_len) | |
587 j = t_len; | |
588 if(i > j) | |
589 icq_RusConv_n(to, &t_in[j], i - j); | |
590 } | |
591 | |
592 void icq_TCPLinkOnDataReceived(icq_TCPLink *plink) | |
593 { | |
594 int process_count=0, recv_result=0; | |
595 char *buffer=plink->buffer; | |
596 | |
597 do { /* while recv_result > 0 */ | |
598 | |
599 int done=0; | |
600 | |
601 /* append received data onto end of buffer */ | |
602 if((recv_result=recv(plink->socket, buffer+plink->buffer_count, | |
603 icq_TCPLinkBufferSize-plink->buffer_count, 0)) < 1) | |
604 { | |
605 /* either there was an error or the remote side has closed | |
606 * the connection - fall out of the loop */ | |
607 continue; | |
608 }; | |
609 | |
610 plink->buffer_count+=recv_result; | |
611 | |
612 #ifdef TCP_BUFFER_TRACE | |
613 printf("received %d bytes from link %x, new buffer count %d\n", | |
614 recv_result, plink, plink->buffer_count); | |
615 | |
616 hex_dump(plink->buffer, plink->buffer_count); | |
617 #endif /*TCP_BUFFER_TRACE*/ | |
618 | |
619 process_count+=recv_result; | |
620 | |
621 /* don't do any packet processing if we're in raw mode */ | |
622 if(plink->mode & TCP_LINK_MODE_RAW) { | |
623 /* notify the app with the new data */ | |
624 if(plink->type == TCP_LINK_CHAT) | |
625 icq_ChatRusConv_n("wk", plink->buffer, plink->buffer_count); | |
626 invoke_callback(plink->icqlink, icq_ChatNotify)(plink->session, | |
627 CHAT_NOTIFY_DATA, plink->buffer_count, plink->buffer); | |
628 plink->buffer_count=0; | |
629 continue; | |
630 } | |
631 | |
632 /* remove packets from the buffer until the buffer is empty | |
633 * or the remaining bytes do not equal a full packet */ | |
634 while((unsigned)plink->buffer_count>sizeof(WORD) && !done) | |
635 { | |
636 WORD packet_size=(*((WORD *)buffer)); | |
637 | |
638 /* warn if the buffer is too small to hold the whole packet */ | |
639 if(packet_size>icq_TCPLinkBufferSize-sizeof(WORD)) | |
640 { | |
641 icq_FmtLog(plink->icqlink, ICQ_LOG_WARNING, "tcplink buffer " | |
642 "overflow, packet size = %d, buffer size = %d, closing link\n", | |
643 packet_size, icq_TCPLinkBufferSize); | |
644 return; | |
645 } | |
646 | |
647 if(packet_size+sizeof(WORD) <= (unsigned)plink->buffer_count) | |
648 { | |
649 /* copy the packet into memory */ | |
650 icq_Packet *p=icq_PacketNew(); | |
651 icq_PacketAppend(p, buffer+sizeof(WORD), packet_size); | |
652 | |
653 /* remove it from the buffer */ | |
654 memcpy(buffer, buffer+packet_size+sizeof(WORD), | |
655 plink->buffer_count-packet_size-sizeof(WORD)); | |
656 | |
657 plink->buffer_count-=(packet_size+sizeof(WORD)); | |
658 | |
659 icq_TCPLinkOnPacketReceived(plink, p); | |
660 } | |
661 else | |
662 { | |
663 /* not enough bytes in buffer to form the complete packet. | |
664 * we're done for now */ | |
665 done=1; | |
666 } | |
667 } /* while packets remain in buffer */ | |
668 | |
669 } while (recv_result > 0); | |
670 | |
671 #ifdef _WIN32 | |
672 if (recv_result <= 0 && WSAGetLastError()!=EWOULDBLOCK) { | |
673 /* receive error - log it */ | |
674 icq_FmtLog(plink->icqlink, ICQ_LOG_WARNING, "recv failed from %d (%d)," | |
675 " closing link\n", plink->remote_uin, WSAGetLastError()); | |
676 #else | |
677 if (recv_result <= 0 && errno!=EWOULDBLOCK) { | |
678 /* receive error - log it */ | |
679 icq_FmtLog(plink->icqlink, ICQ_LOG_WARNING, "recv failed from %d (%d-%s)," | |
680 " closing link\n", plink->remote_uin, errno, strerror(errno)); | |
681 #endif | |
682 | |
683 icq_TCPLinkClose(plink); | |
684 | |
685 } else { | |
686 | |
687 icq_TCPLinkProcessReceived(plink); | |
688 | |
689 } | |
690 | |
691 } | |
692 | |
693 void icq_TCPLinkOnPacketReceived(icq_TCPLink *plink, icq_Packet *p) | |
694 { | |
695 | |
696 #ifdef TCP_RAW_TRACE | |
697 printf("packet received! { length=%d }\n", p->length); | |
698 icq_PacketDump(p); | |
699 #endif | |
700 | |
701 /* Stick packet on ready packet linked icq_List */ | |
702 icq_ListEnqueue(plink->received_queue, p); | |
703 } | |
704 | |
705 void icq_TCPLinkOnConnect(icq_TCPLink *plink) | |
706 { | |
707 #ifdef _WIN32 | |
708 int len; | |
709 #else | |
710 size_t len; | |
711 #endif | |
712 int error; | |
713 | |
714 icq_TimeoutDelete(plink->connect_timeout); | |
715 plink->connect_timeout = NULL; | |
716 | |
717 /* check getsockopt */ | |
718 len=sizeof(error); | |
719 | |
720 #ifndef __BEOS__ | |
721 #ifdef _WIN32 | |
722 getsockopt(plink->socket, SOL_SOCKET, SO_ERROR, (char *)&error, &len); | |
723 #else | |
724 getsockopt(plink->socket, SOL_SOCKET, SO_ERROR, &error, &len); | |
725 #endif | |
726 #endif | |
727 if(!error && (plink->mode & (TCP_LINK_SOCKS_CONNECTING | TCP_LINK_SOCKS_AUTHORIZATION | | |
728 TCP_LINK_SOCKS_AUTHSTATUS | TCP_LINK_SOCKS_NOAUTHSTATUS | | |
729 TCP_LINK_SOCKS_CROSSCONNECT | TCP_LINK_SOCKS_CONNSTATUS))) | |
730 { | |
731 if(plink->mode & TCP_LINK_SOCKS_CONNECTING) | |
732 error = icq_TCPLinkProxyRequestAuthorization(plink); | |
733 else if(plink->mode & TCP_LINK_SOCKS_AUTHORIZATION) | |
734 error = icq_TCPLinkProxyAuthorization(plink); | |
735 else if(plink->mode & TCP_LINK_SOCKS_AUTHSTATUS) | |
736 error = icq_TCPLinkProxyAuthStatus(plink); | |
737 else if(plink->mode & TCP_LINK_SOCKS_NOAUTHSTATUS) | |
738 error = icq_TCPLinkProxyNoAuthStatus(plink); | |
739 else if(plink->mode & TCP_LINK_SOCKS_CROSSCONNECT) | |
740 error = icq_TCPLinkProxyCrossConnect(plink); | |
741 else if(plink->mode & TCP_LINK_SOCKS_CONNSTATUS) | |
742 error = icq_TCPLinkProxyConnectStatus(plink); | |
743 else | |
744 error = EINVAL; | |
745 } | |
746 | |
747 if(error) | |
748 { | |
749 /* connection failed- close the link, which takes care | |
750 * of notifying the app about packets that didn't make it */ | |
751 icq_FmtLog(plink->icqlink, ICQ_LOG_WARNING, "connect failed to %d (%d-%s)," | |
752 " closing link\n", plink->remote_uin, error, strerror(error)); | |
753 | |
754 icq_TCPLinkClose(plink); | |
755 return; | |
756 } | |
757 | |
758 if(plink->mode & (TCP_LINK_SOCKS_CONNECTING | TCP_LINK_SOCKS_AUTHORIZATION | TCP_LINK_SOCKS_AUTHSTATUS | TCP_LINK_SOCKS_NOAUTHSTATUS | TCP_LINK_SOCKS_CROSSCONNECT | TCP_LINK_SOCKS_CONNSTATUS)) | |
759 { | |
760 icq_SocketSetHandler(plink->socket, ICQ_SOCKET_WRITE, NULL, NULL); | |
761 icq_SocketSetHandler(plink->socket, ICQ_SOCKET_READ, | |
2496
f0a2a9afdb77
[gaim-migrate @ 2509]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
762 (icq_SocketHandler)icq_TCPLinkOnConnect, plink); |
2086 | 763 return; |
764 } | |
765 | |
766 len=sizeof(plink->socket_address); | |
767 getsockname(plink->socket, (struct sockaddr *)&plink->socket_address, &len); | |
768 | |
769 icq_FmtLog(plink->icqlink, ICQ_LOG_MESSAGE, | |
770 "connected to uin %d, socket=%d local address=%s:%d remote address=%s:%d\n", | |
771 plink->remote_uin, plink->socket, | |
772 inet_ntoa(*((struct in_addr *)(&plink->socket_address.sin_addr))), | |
773 ntohs(plink->socket_address.sin_port), | |
774 inet_ntoa(*((struct in_addr *)(&plink->remote_address.sin_addr))), | |
775 ntohs(plink->remote_address.sin_port)); | |
776 | |
777 plink->mode&= ~TCP_LINK_MODE_CONNECTING; | |
778 | |
779 icq_SocketSetHandler(plink->socket, ICQ_SOCKET_READ, | |
2496
f0a2a9afdb77
[gaim-migrate @ 2509]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
780 (icq_SocketHandler)icq_TCPLinkOnDataReceived, plink); |
2086 | 781 icq_SocketSetHandler(plink->socket, ICQ_SOCKET_WRITE, NULL, NULL); |
782 | |
783 /* socket is now connected, notify each request that connection | |
784 * has been established and send pending data */ | |
785 while(plink->send_queue->count>0) | |
786 { | |
787 icq_Packet *p=icq_ListDequeue(plink->send_queue); | |
788 if(p->id) | |
789 if(plink->icqlink->icq_RequestNotify) | |
790 (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_CONNECTED, 0, 0); | |
791 icq_TCPLinkSend(plink, p); | |
792 } | |
793 | |
794 /* yeah this probably shouldn't be here. oh well :) */ | |
795 if(plink->type==TCP_LINK_CHAT) | |
796 { | |
797 icq_ChatSessionSetStatus((icq_ChatSession *)plink->session, | |
798 CHAT_STATUS_CONNECTED); | |
799 icq_ChatSessionSetStatus((icq_ChatSession *)plink->session, | |
800 CHAT_STATUS_WAIT_ALLINFO); | |
801 } | |
802 | |
803 if(plink->type==TCP_LINK_FILE) | |
804 { | |
805 icq_FileSessionSetStatus((icq_FileSession *)plink->session, | |
806 FILE_STATUS_CONNECTED); | |
807 } | |
808 | |
809 } | |
810 | |
811 unsigned long icq_TCPLinkSendSeq(icq_TCPLink *plink, icq_Packet *p, | |
812 unsigned long sequence) | |
813 { | |
814 /* append the next sequence number on the packet */ | |
815 if (!sequence) | |
816 sequence=plink->icqlink->d->icq_TCPSequence--; | |
817 p->id=sequence; | |
818 icq_PacketEnd(p); | |
819 icq_PacketAppend32(p, sequence); | |
820 | |
821 /* if the link is currently connecting, queue the packets for | |
822 * later, else send immediately */ | |
823 if(plink->mode & TCP_LINK_MODE_CONNECTING) { | |
824 icq_ListInsert(plink->send_queue, 0, p); | |
825 if(plink->icqlink->icq_RequestNotify) | |
826 (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_CONNECTING, 0, 0); | |
827 } else { | |
828 icq_PacketSend(p, plink->socket); | |
829 if(p->id) | |
830 if(plink->icqlink->icq_RequestNotify) | |
831 (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_SENT, 0, 0); | |
832 icq_PacketDelete(p); | |
833 } | |
834 return sequence; | |
835 } | |
836 | |
837 void icq_TCPLinkSend(icq_TCPLink *plink, icq_Packet *p) | |
838 { | |
839 /* if the link is currently connecting, queue the packets for | |
840 * later, else send immediately */ | |
841 if(plink->mode & TCP_LINK_MODE_CONNECTING) { | |
842 icq_ListInsert(plink->send_queue, 0, p); | |
843 if(plink->icqlink->icq_RequestNotify) | |
844 (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_CONNECTING, 0, 0); | |
845 } else { | |
846 icq_PacketSend(p, plink->socket); | |
847 if(p->id) | |
848 if(plink->icqlink->icq_RequestNotify) | |
849 (*plink->icqlink->icq_RequestNotify)(plink->icqlink, p->id, ICQ_NOTIFY_SENT, 0, 0); | |
850 icq_PacketDelete(p); | |
851 } | |
852 } | |
853 | |
854 void icq_TCPLinkProcessReceived(icq_TCPLink *plink) | |
855 { | |
856 icq_List *plist=plink->received_queue; | |
857 while(plist->count>0) | |
858 | |
859 { | |
860 icq_Packet *p=icq_ListDequeue(plist); | |
861 | |
862 if(plink->mode & TCP_LINK_MODE_HELLOWAIT) | |
863 { | |
864 icq_TCPProcessHello(p, plink); | |
865 } | |
866 else | |
867 { | |
868 | |
869 switch (plink->type) { | |
870 | |
871 case TCP_LINK_MESSAGE: | |
872 icq_TCPProcessPacket(p, plink); | |
873 break; | |
874 | |
875 case TCP_LINK_CHAT: | |
876 icq_TCPProcessChatPacket(p, plink); | |
877 break; | |
878 | |
879 case TCP_LINK_FILE: | |
880 icq_TCPProcessFilePacket(p, plink); | |
881 break; | |
882 | |
883 } | |
884 } | |
885 | |
886 icq_PacketDelete(p); | |
887 } | |
888 | |
889 } | |
890 | |
891 int _icq_FindTCPLink(void *p, va_list data) | |
892 { | |
893 icq_TCPLink *plink=(icq_TCPLink *)p; | |
894 unsigned long uin=va_arg(data, unsigned long); | |
895 int type=va_arg(data, int); | |
896 | |
897 return ( (plink->remote_uin == uin ) && (plink->type == type) ); | |
898 } | |
899 | |
900 icq_TCPLink *icq_FindTCPLink(icq_Link *icqlink, unsigned long uin, int type) | |
901 { | |
902 return icq_ListTraverse(icqlink->d->icq_TCPLinks, _icq_FindTCPLink, uin, type); | |
903 } |