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