1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3 $Id: icqlib.c,v 1.44 2000/07/24 03:10:08 bills Exp $
4 $Log: icqlib.c,v $
5 Revision 1.44 2000/07/24 03:10:08 bills
6 added support for real nickname during TCP transactions like file and
7 chat, instead of using Bill all the time (hmm, where'd I get that from? :)
8
9 Revision 1.43 2000/07/09 22:05:11 bills
10 removed unnecessary functions
11
12 Revision 1.42 2000/07/09 18:28:07 denis
13 Initial memset() in icq_Init() replaced by callback's clearance.
14
15 Revision 1.41 2000/06/15 01:50:39 bills
16 removed *Seq functions
17
18 Revision 1.40 2000/05/10 19:06:59 denis
19 UDP outgoing packet queue was implemented.
20
21 Revision 1.39 2000/05/03 18:12:36 denis
22 Unfinished UDP queue was commented out.
23
24 Revision 1.38 2000/04/10 16:36:04 denis
25 Some more Win32 compatibility from Guillaume Rosanis <grs@mail.com>
26
27 Revision 1.37 2000/04/06 16:38:04 denis
28 icq_*Send*Seq() functions with specified sequence number were added.
29
30 Revision 1.36 2000/04/05 14:37:02 denis
31 Applied patch from "Guillaume R." <grs@mail.com> for basic Win32
32 compatibility.
33
34 Revision 1.35 2000/01/16 03:59:10 bills
35 reworked list code so list_nodes don't need to be inside item structures,
36 removed strlist code and replaced with generic list calls
37
38 Revision 1.34 1999/12/27 16:06:32 bills
39 cleanups
40
41 Revision 1.33 1999/10/03 21:35:55 tim
42 Fixed "url" and "descr" parameters order when sending a URL via TCP.
43
44 Revision 1.32 1999/09/29 16:49:43 denis
45 Host/network/icq byteorder systemized.
46 icq_Init() cleaned up.
47
48 Revision 1.31 1999/07/18 20:15:55 bills
49 changed to use new byte-order functions & contact list functions
50
51 Revision 1.30 1999/07/16 12:27:06 denis
52 Other global variables moved to ICQLINK structure.
53 Initialization of random number generator added in icq_Init()
54 Cleaned up.
55
56 Revision 1.29 1999/07/12 15:13:31 cproch
57 - added definition of ICQLINK to hold session-specific global variabled
58 applications which have more than one connection are now possible
59 - changed nearly every function defintion to support ICQLINK parameter
60
61 Revision 1.28 1999/07/03 02:26:02 bills
62 added new code to support thruSrv arg to SendMessage and SendURL
63
64 Revision 1.27 1999/04/17 19:21:37 bills
65 modified Send* Functions to return DWORD instead of WORD
66
67 Revision 1.26 1999/04/14 14:48:18 denis
68 Switched from icq_Log callback to icq_Fmt function.
69 Cleanups for "strict" compiling (-ansi -pedantic)
70
71 Revision 1.25 1999/04/05 13:14:57 denis
72 Send messages and URLs to 'not in list' users fixed.
73
74 Revision 1.24 1999/03/31 01:43:40 bills
75 added TCP support to SendURL
76
77 Revision 1.23 1999/03/30 22:47:44 lord
78 list of countries now sorted.
79
80 Revision 1.22 1999/03/28 03:18:22 bills
81 enable tcp messaging in icq_SendMessage, uncommented icq_OurPort and
82 icq_OurIp and fixed function names so icqlib compiles
83
84 Revision 1.21 1999/03/25 22:16:43 bills
85 added #include "util.h"
86
87 Revision 1.20 1999/03/24 11:37:36 denis
88 Underscored files with TCP stuff renamed.
89 TCP stuff cleaned up
90 Function names changed to corresponding names.
91 icqlib.c splitted to many small files by subject.
92 C++ comments changed to ANSI C comments.
93
94 Revision 1.19 1999/03/22 20:51:28 bills
95 added code in icq_HandleUserOnline to set/clear new struct entries in
96 icq_ContactItem; added cleanup code in icq_HandleUserOffline for same
97
98 Revision 1.18 1999/03/09 13:14:05 denis
99 Cyrillic recoding removed from URLs
100
101 Revision 1.17 1999/03/05 13:57:54 denis
102 Some cosmetic changes...
103
104 Revision 1.16 1998/12/08 16:00:59 denis
105 Cleaned up a little before releasing
106
107 Revision 1.15 1998/11/25 19:18:16 denis
108 Added close icq_ProxySok in icq_Disconnect
109
110 Revision 1.14 1998/11/25 09:48:49 denis
111 icq_GetProxySok and icq_HandleProxyResponse methods added
112 Connection terminated support added
113
114 Revision 1.13 1998/11/19 12:22:48 denis
115 SOCKS support cleaned a little
116 icq_RecvUrl renamed to icq_RecvURL
117 icq_ProxyAuth added for Username/Password Authentication
118 URL/Description order inverted
119 icq_Quit splitted to icq_Logout and icq_Disconnect
120 icq_ProxyName and icq_ProxyPass range checking added
121
122 Revision 1.12 1998/11/18 16:21:29 denis
123 Fixed SOCKS5 proxy support
124
125 */
126
127 #include "icqlib.h"
128
129 #include <stdlib.h>
130
131 #ifndef _WIN32
132 #include <unistd.h>
133 #endif
134
135 #include <time.h>
136
137 #ifdef _WIN32
138 #include <winsock.h>
139 #else
140 #include <netdb.h>
141 #include <sys/socket.h>
142 #endif
143
144 #include <sys/stat.h>
145
146 #ifndef _WIN32
147 #include <sys/time.h>
148 #include <netinet/in.h>
149 #endif
150
151 #include "util.h"
152 #include "icqtypes.h"
153 #include "icq.h"
154 #include "udp.h"
155 #include "tcp.h"
156 #include "queue.h"
157
158 int icq_Russian = FALSE;
159 BYTE icq_LogLevel = 0;
160
icq_SendMessage(ICQLINK * link,DWORD uin,const char * text,BYTE thruSrv)161 DWORD icq_SendMessage(ICQLINK *link, DWORD uin, const char *text, BYTE thruSrv)
162 {
163 if(thruSrv==ICQ_SEND_THRUSERVER)
164 return icq_UDPSendMessage(link, uin, text);
165 else if(thruSrv==ICQ_SEND_DIRECT)
166 return icq_TCPSendMessage(link, uin, text);
167 else if(thruSrv==ICQ_SEND_BESTWAY)
168 {
169 icq_ContactItem *pcontact=icq_ContactFind(link, uin);
170 if(pcontact)
171 {
172 if(pcontact->tcp_flag == 0x04)
173 return icq_TCPSendMessage(link, uin, text);
174 else
175 return icq_UDPSendMessage(link, uin, text);
176 }
177 else
178 {
179 return icq_UDPSendMessage(link, uin, text);
180 }
181 }
182 return 0;
183 }
184
icq_SendURL(ICQLINK * link,DWORD uin,const char * url,const char * descr,BYTE thruSrv)185 DWORD icq_SendURL(ICQLINK *link, DWORD uin, const char *url, const char *descr, BYTE thruSrv)
186 {
187 if(thruSrv==ICQ_SEND_THRUSERVER)
188 return icq_UDPSendURL(link, uin, url, descr);
189 else if(thruSrv==ICQ_SEND_DIRECT)
190 return icq_TCPSendURL(link, uin, descr, url);
191 else if(thruSrv==ICQ_SEND_BESTWAY)
192 {
193 icq_ContactItem *pcontact=icq_ContactFind(link, uin);
194 if(pcontact)
195 {
196 if(pcontact->tcp_flag == 0x04)
197 return icq_TCPSendURL(link, uin, descr, url);
198 else
199 return icq_UDPSendURL(link, uin, url, descr);
200 }
201 else
202 {
203 return icq_UDPSendURL(link, uin, url, descr);
204 }
205 }
206 return 0;
207 }
208
icq_Init(ICQLINK * link,DWORD uin,const char * password,const char * nick)209 void icq_Init(ICQLINK *link, DWORD uin, const char *password,
210 const char *nick)
211 {
212 srand(time(0L));
213 /* memset(link, 0, sizeof(ICQLINK)); */
214
215 /* Initialize all callbacks */
216 link->icq_Logged = 0L;
217 link->icq_Disconnected = 0L;
218 link->icq_RecvMessage = 0L;
219 link->icq_RecvURL = 0L;
220 link->icq_RecvWebPager = 0L;
221 link->icq_RecvMailExpress = 0L;
222 link->icq_RecvChatReq = 0L;
223 link->icq_RecvFileReq = 0L;
224 link->icq_RecvAdded = 0L;
225 link->icq_RecvAuthReq = 0L;
226 link->icq_UserFound = 0L;
227 link->icq_SearchDone = 0L;
228 link->icq_UserOnline = 0L;
229 link->icq_UserOffline = 0L;
230 link->icq_UserStatusUpdate = 0L;
231 link->icq_InfoReply = 0L;
232 link->icq_ExtInfoReply = 0L;
233 link->icq_WrongPassword = 0L;
234 link->icq_InvalidUIN = 0L;
235 link->icq_Log = 0L;
236 link->icq_SrvAck = 0L;
237 link->icq_RequestNotify = 0L;
238 link->icq_NewUIN = 0L;
239 link->icq_SetTimeout = 0L;
240 link->icq_MetaUserFound = 0L;
241 link->icq_MetaUserInfo = 0L;
242 link->icq_MetaUserWork = 0L;
243 link->icq_MetaUserMore = 0L;
244 link->icq_MetaUserAbout = 0L;
245 link->icq_MetaUserInterests = 0L;
246 link->icq_MetaUserAffiliations = 0L;
247 link->icq_MetaUserHomePageCategory = 0L;
248
249 /* General stuff */
250 link->icq_Uin = uin;
251 link->icq_Password = strdup(password);
252 link->icq_Nick = strdup(nick);
253 link->icq_OurIP = -1;
254 link->icq_OurPort = 0;
255 link->icq_ContactList = list_new();
256 link->icq_Status = -1;
257
258 /* UDP stuff */
259 link->icq_UDPSok = -1;
260 memset(link->icq_UDPServMess, FALSE, sizeof(link->icq_UDPServMess));
261 link->icq_UDPSeqNum1 = 0;
262 link->icq_UDPSeqNum2 = 0;
263 link->icq_UDPSession = 0;
264 icq_UDPQueueNew(link);
265
266 icq_TCPInit(link);
267
268 /* Proxy stuff */
269 link->icq_UseProxy = 0;
270 link->icq_ProxyHost = 0L;
271 link->icq_ProxyIP = -1;
272 link->icq_ProxyPort = 0;
273 link->icq_ProxyAuth = 0;
274 link->icq_ProxyName = 0L;
275 link->icq_ProxyPass = 0L;
276 link->icq_ProxySok = -1;
277 link->icq_ProxyOurPort = 0;
278 link->icq_ProxyDestIP = -1;
279 link->icq_ProxyDestPort = 0;
280 }
281
icq_Done(ICQLINK * link)282 void icq_Done(ICQLINK *link)
283 {
284 icq_TCPDone(link);
285 if(link->icq_Password)
286 free(link->icq_Password);
287 if(link->icq_Nick)
288 free(link->icq_Nick);
289 if(link->icq_ContactList)
290 list_delete(link->icq_ContactList, icq_ContactDelete);
291 icq_UDPQueueDelete(link);
292 }
293
294 /******************************
295 Main function connects gets icq_Uin
296 and icq_Password and logins in and sits
297 in a loop waiting for server responses.
298 *******************************/
icq_Main(ICQLINK * link)299 void icq_Main(ICQLINK *link)
300 {
301 struct timeval tv;
302 fd_set readfds;
303
304 tv.tv_sec = 0;
305 tv.tv_usec = 0;
306 FD_ZERO(&readfds);
307 FD_SET(link->icq_UDPSok, &readfds);
308 select(link->icq_UDPSok+1, &readfds, 0L, 0L, &tv);
309 if(FD_ISSET(link->icq_UDPSok, &readfds))
310 icq_HandleServerResponse(link);
311 icq_TCPMain(link);
312 }
313
314 /**********************************
315 Connects to hostname on port port
316 hostname can be DNS or nnn.nnn.nnn.nnn
317 write out messages to the FD aux
318 ***********************************/
icq_Connect(ICQLINK * link,const char * hostname,int port)319 int icq_Connect(ICQLINK *link, const char *hostname, int port)
320 {
321 char buf[1024]; /*, un = 1;*/
322 /* char tmpbuf[256], our_host[256]*/
323 int conct, res;
324 unsigned int length;
325 struct sockaddr_in sin, prsin; /* used to store inet addr stuff */
326 struct hostent *host_struct; /* used in DNS llokup */
327
328 link->icq_UDPSok = socket(AF_INET, SOCK_DGRAM, 0);/* create the unconnected socket*/
329 if(link->icq_UDPSok == -1)
330 {
331 icq_FmtLog(link, ICQ_LOG_FATAL, "Socket creation failed\n");
332 return -1;
333 }
334 icq_FmtLog(link, ICQ_LOG_MESSAGE, "Socket created attempting to connect\n");
335 sin.sin_addr.s_addr = INADDR_ANY;
336 sin.sin_family = AF_INET; /* we're using the inet not appletalk*/
337 sin.sin_port = 0;
338 if(bind(link->icq_UDPSok, (struct sockaddr*)&sin, sizeof(struct sockaddr))<0)
339 {
340 icq_FmtLog(link, ICQ_LOG_FATAL, "Can't bind socket to free port\n");
341 return -1;
342 }
343 length = sizeof(sin);
344 getsockname(link->icq_UDPSok, (struct sockaddr*)&sin, &length);
345 link->icq_ProxyOurPort = ntohs(sin.sin_port);
346 if(link->icq_UseProxy)
347 {
348 icq_FmtLog(link, ICQ_LOG_MESSAGE, "[SOCKS] Trying to use SOCKS5 proxy\n");
349 prsin.sin_addr.s_addr = inet_addr(link->icq_ProxyHost);
350 if(prsin.sin_addr.s_addr == (unsigned long)-1) /* name isn't n.n.n.n so must be DNS */
351 {
352 host_struct = gethostbyname(link->icq_ProxyHost);
353 if(host_struct == 0L)
354 {
355 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Can't find hostname: %s\n", link->icq_ProxyHost);
356 return -1;
357 }
358 prsin.sin_addr = *((struct in_addr*)host_struct->h_addr);
359 }
360 link->icq_ProxyIP = ntohl(prsin.sin_addr.s_addr);
361 prsin.sin_family = AF_INET; /* we're using the inet not appletalk*/
362 prsin.sin_port = htons(link->icq_ProxyPort); /* port */
363 link->icq_ProxySok = socket(AF_INET, SOCK_STREAM, 0);/* create the unconnected socket*/
364 if(link->icq_ProxySok == -1)
365 {
366 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Socket creation failed\n");
367 return -1;
368 }
369 icq_FmtLog(link, ICQ_LOG_MESSAGE, "[SOCKS] Socket created attempting to connect\n");
370 conct = connect(link->icq_ProxySok, (struct sockaddr *) &prsin, sizeof(prsin));
371 if(conct == -1) /* did we connect ?*/
372 {
373 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n");
374 return -1;
375 }
376 buf[0] = 5; /* protocol version */
377 buf[1] = 1; /* number of methods */
378 if(!strlen(link->icq_ProxyName) || !strlen(link->icq_ProxyPass) || !link->icq_ProxyAuth)
379 buf[2] = 0; /* no authorization required */
380 else
381 buf[2] = 2; /* method username/password */
382 #ifdef _WIN32
383 send(link->icq_ProxySok, buf, 3, 0);
384 res = recv(link->icq_ProxySok, buf, 2, 0);
385 #else
386 write(link->icq_ProxySok, buf, 3);
387 res = read(link->icq_ProxySok, buf, 2);
388 #endif
389 if(strlen(link->icq_ProxyName) && strlen(link->icq_ProxyPass) && link->icq_ProxyAuth)
390 {
391 if(res != 2 || buf[0] != 5 || buf[1] != 2) /* username/password authentication*/
392 {
393 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n");
394 #ifdef _WIN32
395 closesocket(link->icq_ProxySok);
396 #else
397 close(link->icq_ProxySok);
398 #endif
399 return -1;
400 }
401 buf[0] = 1; /* version of subnegotiation */
402 buf[1] = strlen(link->icq_ProxyName);
403 memcpy(&buf[2], link->icq_ProxyName, buf[1]);
404 buf[2+buf[1]] = strlen(link->icq_ProxyPass);
405 memcpy(&buf[3+buf[1]], link->icq_ProxyPass, buf[2+buf[1]]);
406 #ifdef _WIN32
407 send(link->icq_ProxySok, buf, buf[1]+buf[2+buf[1]]+3, 0);
408 res = recv(link->icq_ProxySok, buf, 2, 0);
409 #else
410 write(link->icq_ProxySok, buf, buf[1]+buf[2+buf[1]]+3);
411 res = read(link->icq_ProxySok, buf, 2);
412 #endif
413 if(res != 2 || buf[0] != 1 || buf[1] != 0)
414 {
415 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Authorization failure\n");
416 #ifdef _WIN32
417 closesocket(link->icq_ProxySok);
418 #else
419 close(link->icq_ProxySok);
420 #endif
421 return -1;
422 }
423 }
424 else
425 {
426 if(res != 2 || buf[0] != 5 || buf[1] != 0) /* no authentication required */
427 {
428 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Authentication method incorrect\n");
429 #ifdef _WIN32
430 closesocket(link->icq_ProxySok);
431 #else
432 close(link->icq_ProxySok);
433 #endif
434 return -1;
435 }
436 }
437 buf[0] = 5; /* protocol version */
438 buf[1] = 3; /* command UDP associate */
439 buf[2] = 0; /* reserved */
440 buf[3] = 1; /* address type IP v4 */
441 buf[4] = (char)0;
442 buf[5] = (char)0;
443 buf[6] = (char)0;
444 buf[7] = (char)0;
445 *(unsigned short*)&buf[8] = htons(link->icq_ProxyOurPort);
446 /* memcpy(&buf[8], &link->icq_ProxyOurPort, 2); */
447 #ifdef _WIN32
448 send(link->icq_ProxySok, buf, 10, 0);
449 res = recv(link->icq_ProxySok, buf, 10, 0);
450 #else
451 write(link->icq_ProxySok, buf, 10);
452 res = read(link->icq_ProxySok, buf, 10);
453 #endif
454 if(res != 10 || buf[0] != 5 || buf[1] != 0)
455 {
456 switch(buf[1])
457 {
458 case 1:
459 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] General SOCKS server failure\n");
460 break;
461 case 2:
462 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Connection not allowed by ruleset\n");
463 break;
464 case 3:
465 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Network unreachable\n");
466 break;
467 case 4:
468 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Host unreachable\n");
469 break;
470 case 5:
471 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Connection refused\n");
472 break;
473 case 6:
474 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] TTL expired\n");
475 break;
476 case 7:
477 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Command not supported\n");
478 break;
479 case 8:
480 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Address type not supported\n");
481 break;
482 default:
483 icq_FmtLog(link, ICQ_LOG_FATAL, "[SOCKS] Unknown SOCKS server failure\n");
484 break;
485 }
486 #ifdef _WIN32
487 closesocket(link->icq_ProxySok);
488 #else
489 close(link->icq_ProxySok);
490 #endif
491 return -1;
492 }
493 }
494 sin.sin_addr.s_addr = inet_addr(hostname); /* checks for n.n.n.n notation */
495 if(sin.sin_addr.s_addr == (unsigned long)-1) /* name isn't n.n.n.n so must be DNS */
496 {
497 host_struct = gethostbyname(hostname);
498 if(host_struct == 0L)
499 {
500 icq_FmtLog(link, ICQ_LOG_FATAL, "Can't find hostname: %s\n", hostname);
501 if(link->icq_UseProxy)
502 {
503 #ifdef _WIN32
504 closesocket(link->icq_ProxySok);
505 #else
506 close(link->icq_ProxySok);
507 #endif
508 }
509 return -1;
510 }
511 sin.sin_addr = *((struct in_addr *)host_struct->h_addr);
512 }
513 if(link->icq_UseProxy)
514 {
515 link->icq_ProxyDestIP = ntohl(sin.sin_addr.s_addr);
516 memcpy(&sin.sin_addr.s_addr, &buf[4], 4);
517 }
518 sin.sin_family = AF_INET; /* we're using the inet not appletalk*/
519 sin.sin_port = htons(port); /* port */
520 if(link->icq_UseProxy)
521 {
522 link->icq_ProxyDestPort = port;
523 memcpy(&sin.sin_port, &buf[8], 2);
524 }
525 conct = connect(link->icq_UDPSok, (struct sockaddr*)&sin, sizeof(sin));
526 if(conct == -1) /* did we connect ?*/
527 {
528 icq_FmtLog(link, ICQ_LOG_FATAL, "Connection refused\n");
529 if(link->icq_UseProxy)
530 {
531 #ifdef _WIN32
532 closesocket(link->icq_ProxySok);
533 #else
534 close(link->icq_ProxySok);
535 #endif
536 }
537 return -1;
538 }
539 length = sizeof(sin) ;
540 getsockname(link->icq_UDPSok, (struct sockaddr*)&sin, &length);
541 link->icq_OurIP = ntohl(sin.sin_addr.s_addr);
542 link->icq_OurPort = ntohs(sin.sin_port);
543 return link->icq_UDPSok;
544 }
545
icq_Disconnect(ICQLINK * link)546 void icq_Disconnect(ICQLINK *link)
547 {
548 #ifdef _WIN32
549 closesocket(link->icq_UDPSok);
550 #else
551 close(link->icq_UDPSok);
552 #endif
553 if(link->icq_UseProxy)
554 {
555 #ifdef _WIN32
556 closesocket(link->icq_ProxySok);
557 #else
558 close(link->icq_ProxySok);
559 #endif
560 }
561 icq_UDPQueueFree(link);
562 }
563
564 /*
565 void icq_InitNewUser(const char *hostname, DWORD port)
566 {
567 srv_net_icq_pak pak;
568 int s;
569 struct timeval tv;
570 fd_set readfds;
571
572 icq_Connect(hostname, port);
573 if((icq_UDPSok == -1) || (icq_UDPSok == 0))
574 {
575 printf("Couldn't establish connection\n");
576 exit(1);
577 }
578 icq_RegNewUser(icq_Password);
579 for(;;)
580 {
581 tv.tv_sec = 2;
582 tv.tv_usec = 500000;
583
584 FD_ZERO(&readfds);
585 FD_SET(icq_UDPSok, &readfds);
586
587 select(icq_UDPSok+1, &readfds, 0L, 0L, &tv);
588
589 if(FD_ISSET(icq_UDPSok, &readfds))
590 {
591 s = icq_UDPSockRead(icq_UDPSok, &pak.head, sizeof(pak));
592 if(icqtohs(pak.head.cmd) == SRV_NEW_UIN)
593 {
594 icq_Uin = icqtohl(&pak.data[2]);
595 return;
596 }
597 }
598 }
599 }
600 */
601
602 /************************
603 icq_UDPServMess functions
604 *************************/
icq_GetServMess(ICQLINK * link,WORD num)605 BOOL icq_GetServMess(ICQLINK *link, WORD num)
606 {
607 return ((link->icq_UDPServMess[num/8] & (1 << (num%8))) >> (num%8));
608 }
609
icq_SetServMess(ICQLINK * link,WORD num)610 void icq_SetServMess(ICQLINK *link, WORD num)
611 {
612 link->icq_UDPServMess[num/8] |= (1 << (num%8));
613 }
614
icq_GetSok(ICQLINK * link)615 int icq_GetSok(ICQLINK *link)
616 {
617 return link->icq_UDPSok;
618 }
619