1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
4 * $Id: icqlib.c 2096 2001-07-31 01:00:39Z warmenhoven $
6 * Copyright (C) 1998-2001, Denis V. Dmitrienko <denis@null.net> and
7 * Bill Soudan <soudan@kde.org>
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.
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.
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.
33 #include <sys/socket.h>
43 #include "socketmanager.h"
46 int icq_Russian
= FALSE
;
47 BYTE icq_LogLevel
= 0;
49 DWORD
icq_SendMessage(icq_Link
*icqlink
, DWORD uin
, const char *text
,
52 if(thruSrv
==ICQ_SEND_THRUSERVER
)
53 return icq_UDPSendMessage(icqlink
, uin
, text
);
54 else if(thruSrv
==ICQ_SEND_DIRECT
)
55 return icq_TCPSendMessage(icqlink
, uin
, text
);
56 else if(thruSrv
==ICQ_SEND_BESTWAY
)
58 icq_ContactItem
*pcontact
=icq_ContactFind(icqlink
, uin
);
61 if(pcontact
->tcp_flag
== 0x04)
62 return icq_TCPSendMessage(icqlink
, uin
, text
);
64 return icq_UDPSendMessage(icqlink
, uin
, text
);
68 return icq_UDPSendMessage(icqlink
, uin
, text
);
74 DWORD
icq_SendURL(icq_Link
*icqlink
, DWORD uin
, const char *url
,
75 const char *descr
, BYTE thruSrv
)
77 if(thruSrv
==ICQ_SEND_THRUSERVER
)
78 return icq_UDPSendURL(icqlink
, uin
, url
, descr
);
79 else if(thruSrv
==ICQ_SEND_DIRECT
)
80 return icq_TCPSendURL(icqlink
, uin
, descr
, url
);
81 else if(thruSrv
==ICQ_SEND_BESTWAY
)
83 icq_ContactItem
*pcontact
=icq_ContactFind(icqlink
, uin
);
86 if(pcontact
->tcp_flag
== 0x04)
87 return icq_TCPSendURL(icqlink
, uin
, descr
, url
);
89 return icq_UDPSendURL(icqlink
, uin
, url
, descr
);
93 return icq_UDPSendURL(icqlink
, uin
, url
, descr
);
99 static int icqlib_initialized
= 0;
105 /* initialize internal lists, if necessary */
107 icq_SocketList
= icq_ListNew();
109 if (!icq_TimeoutList
)
111 icq_TimeoutList
= icq_ListNew();
112 icq_TimeoutList
->compare_function
=
113 (icq_ListCompareFunc
)icq_TimeoutCompare
;
116 icqlib_initialized
= 1;
119 icq_Link
*icq_LinkNew(DWORD uin
, const char *password
, const char *nick
,
120 unsigned char useTCP
)
122 icq_Link
*icqlink
= (icq_Link
*)malloc(sizeof(icq_Link
));
124 icq_LinkInit(icqlink
, uin
, password
, nick
, useTCP
);
129 void icq_LinkInit(icq_Link
*icqlink
, DWORD uin
, const char *password
,
130 const char *nick
, unsigned char useTCP
)
132 icqlink
->d
= (icq_LinkPrivate
*)malloc(sizeof(icq_LinkPrivate
));
134 if (!icqlib_initialized
)
137 /* Initialize all callbacks */
138 icqlink
->icq_Logged
= 0L;
139 icqlink
->icq_Disconnected
= 0L;
140 icqlink
->icq_RecvMessage
= 0L;
141 icqlink
->icq_RecvURL
= 0L;
142 icqlink
->icq_RecvContactList
= 0L;
143 icqlink
->icq_RecvWebPager
= 0L;
144 icqlink
->icq_RecvMailExpress
= 0L;
145 icqlink
->icq_RecvChatReq
= 0L;
146 icqlink
->icq_RecvFileReq
= 0L;
147 icqlink
->icq_RecvAdded
= 0L;
148 icqlink
->icq_RecvAuthReq
= 0L;
149 icqlink
->icq_UserFound
= 0L;
150 icqlink
->icq_SearchDone
= 0L;
151 icqlink
->icq_UpdateSuccess
= 0L;
152 icqlink
->icq_UpdateFailure
= 0L;
153 icqlink
->icq_UserOnline
= 0L;
154 icqlink
->icq_UserOffline
= 0L;
155 icqlink
->icq_UserStatusUpdate
= 0L;
156 icqlink
->icq_InfoReply
= 0L;
157 icqlink
->icq_ExtInfoReply
= 0L;
158 icqlink
->icq_WrongPassword
= 0L;
159 icqlink
->icq_InvalidUIN
= 0L;
160 icqlink
->icq_Log
= 0L;
161 icqlink
->icq_SrvAck
= 0L;
162 icqlink
->icq_RequestNotify
= 0L;
163 icqlink
->icq_NewUIN
= 0L;
164 icqlink
->icq_MetaUserFound
= 0L;
165 icqlink
->icq_MetaUserInfo
= 0L;
166 icqlink
->icq_MetaUserWork
= 0L;
167 icqlink
->icq_MetaUserMore
= 0L;
168 icqlink
->icq_MetaUserAbout
= 0L;
169 icqlink
->icq_MetaUserInterests
= 0L;
170 icqlink
->icq_MetaUserAffiliations
= 0L;
171 icqlink
->icq_MetaUserHomePageCategory
= 0L;
174 icqlink
->icq_Uin
= uin
;
175 icqlink
->icq_Password
= strdup(password
);
176 icqlink
->icq_Nick
= strdup(nick
);
177 icqlink
->icq_OurIP
= -1;
178 icqlink
->icq_OurPort
= 0;
179 icqlink
->d
->icq_ContactList
= icq_ListNew();
180 icqlink
->icq_Status
= -1;
181 icqlink
->icq_UserData
= 0L;
184 icqlink
->icq_UDPSok
= -1;
185 memset(icqlink
->d
->icq_UDPServMess
, FALSE
,
186 sizeof(icqlink
->d
->icq_UDPServMess
));
187 icqlink
->d
->icq_UDPSeqNum1
= 0;
188 icqlink
->d
->icq_UDPSeqNum2
= 0;
189 icqlink
->d
->icq_UDPSession
= 0;
190 icq_UDPQueueNew(icqlink
);
193 icqlink
->icq_UseTCP
= useTCP
;
195 icq_TCPInit(icqlink
);
198 icqlink
->icq_UseProxy
= 0;
199 icqlink
->icq_ProxyHost
= 0L;
200 icqlink
->icq_ProxyIP
= -1;
201 icqlink
->icq_ProxyPort
= 0;
202 icqlink
->icq_ProxyAuth
= 0;
203 icqlink
->icq_ProxyName
= 0L;
204 icqlink
->icq_ProxyPass
= 0L;
205 icqlink
->icq_ProxySok
= -1;
206 icqlink
->icq_ProxyOurPort
= 0;
207 icqlink
->icq_ProxyDestIP
= -1;
208 icqlink
->icq_ProxyDestPort
= 0;
211 void icq_LinkDestroy(icq_Link
*icqlink
)
213 if(icqlink
->icq_UseTCP
)
214 icq_TCPDone(icqlink
);
215 if(icqlink
->icq_Password
)
216 free(icqlink
->icq_Password
);
217 if(icqlink
->icq_Nick
)
218 free(icqlink
->icq_Nick
);
219 if(icqlink
->d
->icq_ContactList
)
220 icq_ListDelete(icqlink
->d
->icq_ContactList
, icq_ContactDelete
);
221 icq_UDPQueueDelete(icqlink
);
225 void icq_LinkDelete(icq_Link
*icqlink
)
227 icq_LinkDestroy(icqlink
);
231 /******************************
232 Main function connects gets icq_Uin
233 and icq_Password and logins in and sits
234 in a loop waiting for server responses.
235 *******************************/
241 /**********************************
242 Connects to hostname on port port
243 hostname can be DNS or nnn.nnn.nnn.nnn
244 write out messages to the FD aux
245 ***********************************/
246 int icq_Connect(icq_Link
*icqlink
, const char *hostname
, int port
)
248 char buf
[1024]; /*, un = 1;*/
249 /* char tmpbuf[256], our_host[256]*/
252 struct sockaddr_in saddr
, prsin
; /* used to store inet addr stuff */
253 struct hostent
*host_struct
; /* used in DNS llokup */
255 /* create the unconnected socket*/
256 icqlink
->icq_UDPSok
= icq_SocketNew(AF_INET
, SOCK_DGRAM
, 0);
258 if(icqlink
->icq_UDPSok
== -1)
260 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "Socket creation failed\n");
263 icq_FmtLog(icqlink
, ICQ_LOG_MESSAGE
, "Socket created attempting to connect\n");
264 saddr
.sin_addr
.s_addr
= INADDR_ANY
;
265 saddr
.sin_family
= AF_INET
; /* we're using the inet not appletalk*/
267 if(bind(icqlink
->icq_UDPSok
, (struct sockaddr
*)&saddr
, sizeof(struct sockaddr
))<0)
269 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "Can't bind socket to free port\n");
270 icq_SocketDelete(icqlink
->icq_UDPSok
);
271 icqlink
->icq_UDPSok
= -1;
274 length
= sizeof(saddr
);
275 getsockname(icqlink
->icq_UDPSok
, (struct sockaddr
*)&saddr
, &length
);
276 icqlink
->icq_ProxyOurPort
= ntohs(saddr
.sin_port
);
277 if(icqlink
->icq_UseProxy
)
279 int hasName
= icqlink
->icq_ProxyName
&& strlen(icqlink
->icq_ProxyName
);
280 int hasPass
= icqlink
->icq_ProxyPass
&& strlen(icqlink
->icq_ProxyPass
);
281 int authEnabled
= icqlink
->icq_ProxyAuth
&& hasName
&& hasPass
;
283 icq_FmtLog(icqlink
, ICQ_LOG_MESSAGE
, "[SOCKS] Trying to use SOCKS5 proxy\n");
284 prsin
.sin_addr
.s_addr
= inet_addr(icqlink
->icq_ProxyHost
);
285 if(prsin
.sin_addr
.s_addr
== (unsigned long)-1) /* name isn't n.n.n.n so must be DNS */
287 host_struct
= gethostbyname(icqlink
->icq_ProxyHost
);
288 if(host_struct
== 0L)
290 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Can't find hostname: %s\n", icqlink
->icq_ProxyHost
);
293 prsin
.sin_addr
= *((struct in_addr
*)host_struct
->h_addr
);
295 icqlink
->icq_ProxyIP
= ntohl(prsin
.sin_addr
.s_addr
);
296 prsin
.sin_family
= AF_INET
; /* we're using the inet not appletalk*/
297 prsin
.sin_port
= htons(icqlink
->icq_ProxyPort
); /* port */
299 /* create the unconnected socket*/
300 icqlink
->icq_ProxySok
= icq_SocketNew(AF_INET
, SOCK_STREAM
, 0);
302 if(icqlink
->icq_ProxySok
== -1)
304 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Socket creation failed\n");
307 icq_FmtLog(icqlink
, ICQ_LOG_MESSAGE
, "[SOCKS] Socket created attempting to connect\n");
308 conct
= connect(icqlink
->icq_ProxySok
, (struct sockaddr
*) &prsin
, sizeof(prsin
));
309 if(conct
== -1) /* did we connect ?*/
311 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Connection refused\n");
314 buf
[0] = 5; /* protocol version */
315 buf
[1] = 1; /* number of methods */
316 buf
[2] = authEnabled
? 2 : 0; /* authentication method */
319 send(icqlink
->icq_ProxySok
, buf
, 3, 0);
320 res
= recv(icqlink
->icq_ProxySok
, buf
, 2, 0);
322 write(icqlink
->icq_ProxySok
, buf
, 3);
323 res
= read(icqlink
->icq_ProxySok
, buf
, 2);
328 if(res
!= 2 || buf
[0] != 5 || buf
[1] != 2) /* username/password authentication*/
330 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Authentication method incorrect\n");
331 icq_SocketDelete(icqlink
->icq_ProxySok
);
334 buf
[0] = 1; /* version of subnegotiation */
335 buf
[1] = strlen(icqlink
->icq_ProxyName
);
336 memcpy(&buf
[2], icqlink
->icq_ProxyName
, buf
[1]);
337 buf
[2+buf
[1]] = strlen(icqlink
->icq_ProxyPass
);
338 memcpy(&buf
[3+buf
[1]], icqlink
->icq_ProxyPass
, buf
[2+buf
[1]]);
340 send(icqlink
->icq_ProxySok
, buf
, buf
[1]+buf
[2+buf
[1]]+3, 0);
341 res
= recv(icqlink
->icq_ProxySok
, buf
, 2, 0);
343 write(icqlink
->icq_ProxySok
, buf
, buf
[1]+buf
[2+buf
[1]]+3);
344 res
= read(icqlink
->icq_ProxySok
, buf
, 2);
346 if(res
!= 2 || buf
[0] != 1 || buf
[1] != 0)
348 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Authorization failure\n");
349 icq_SocketDelete(icqlink
->icq_ProxySok
);
355 if(res
!= 2 || buf
[0] != 5 || buf
[1] != 0) /* no authentication required */
357 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Authentication method incorrect\n");
358 icq_SocketDelete(icqlink
->icq_ProxySok
);
362 buf
[0] = 5; /* protocol version */
363 buf
[1] = 3; /* command UDP associate */
364 buf
[2] = 0; /* reserved */
365 buf
[3] = 1; /* address type IP v4 */
370 *(unsigned short*)&buf
[8] = htons(icqlink
->icq_ProxyOurPort
);
371 /* memcpy(&buf[8], &icqlink->icq_ProxyOurPort, 2); */
373 send(icqlink
->icq_ProxySok
, buf
, 10, 0);
374 res
= recv(icqlink
->icq_ProxySok
, buf
, 10, 0);
376 write(icqlink
->icq_ProxySok
, buf
, 10);
377 res
= read(icqlink
->icq_ProxySok
, buf
, 10);
379 if(res
!= 10 || buf
[0] != 5 || buf
[1] != 0)
384 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] General SOCKS server failure\n");
387 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Connection not allowed by ruleset\n");
390 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Network unreachable\n");
393 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Host unreachable\n");
396 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Connection refused\n");
399 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] TTL expired\n");
402 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Command not supported\n");
405 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Address type not supported\n");
408 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "[SOCKS] Unknown SOCKS server failure\n");
411 icq_SocketDelete(icqlink
->icq_ProxySok
);
412 icqlink
->icq_ProxySok
= -1;
416 saddr
.sin_addr
.s_addr
= inet_addr(hostname
); /* checks for n.n.n.n notation */
417 if(saddr
.sin_addr
.s_addr
== (unsigned long)-1) /* name isn't n.n.n.n so must be DNS */
419 host_struct
= gethostbyname(hostname
);
420 if(host_struct
== 0L)
422 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "Can't find hostname: %s\n", hostname
);
423 if(icqlink
->icq_UseProxy
)
425 icq_SocketDelete(icqlink
->icq_ProxySok
);
429 saddr
.sin_addr
= *((struct in_addr
*)host_struct
->h_addr
);
431 if(icqlink
->icq_UseProxy
)
433 icqlink
->icq_ProxyDestIP
= ntohl(saddr
.sin_addr
.s_addr
);
434 memcpy(&saddr
.sin_addr
.s_addr
, &buf
[4], 4);
436 saddr
.sin_family
= AF_INET
; /* we're using the inet not appletalk*/
437 saddr
.sin_port
= htons(port
); /* port */
438 if(icqlink
->icq_UseProxy
)
440 icqlink
->icq_ProxyDestPort
= port
;
441 memcpy(&saddr
.sin_port
, &buf
[8], 2);
443 conct
= connect(icqlink
->icq_UDPSok
, (struct sockaddr
*)&saddr
, sizeof(saddr
));
444 if(conct
== -1) /* did we connect ?*/
446 icq_FmtLog(icqlink
, ICQ_LOG_FATAL
, "Connection refused\n");
447 if(icqlink
->icq_UseProxy
)
449 icq_SocketDelete(icqlink
->icq_ProxySok
);
453 length
= sizeof(saddr
) ;
454 getsockname(icqlink
->icq_UDPSok
, (struct sockaddr
*)&saddr
, &length
);
455 icqlink
->icq_OurIP
= ntohl(saddr
.sin_addr
.s_addr
);
456 icqlink
->icq_OurPort
= ntohs(saddr
.sin_port
);
458 /* sockets are ready to receive data - install handlers */
459 icq_SocketSetHandler(icqlink
->icq_UDPSok
, ICQ_SOCKET_READ
,
460 (icq_SocketHandler
)icq_HandleServerResponse
, icqlink
);
461 if (icqlink
->icq_UseProxy
)
462 icq_SocketSetHandler(icqlink
->icq_ProxySok
, ICQ_SOCKET_READ
,
463 (icq_SocketHandler
)icq_HandleProxyResponse
, icqlink
);
464 return icqlink
->icq_UDPSok
;
467 void icq_Disconnect(icq_Link
*icqlink
)
469 icq_SocketDelete(icqlink
->icq_UDPSok
);
470 if(icqlink
->icq_UseProxy
)
471 icq_SocketDelete(icqlink
->icq_ProxySok
);
472 icq_UDPQueueFree(icqlink
);
476 void icq_InitNewUser(const char *hostname, DWORD port)
483 icq_Connect(hostname, port);
484 if((icq_UDPSok == -1) || (icq_UDPSok == 0))
486 printf("Couldn't establish connection\n");
489 icq_RegNewUser(icq_Password);
496 FD_SET(icq_UDPSok, &readfds);
498 select(icq_UDPSok+1, &readfds, 0L, 0L, &tv);
500 if(FD_ISSET(icq_UDPSok, &readfds))
502 s = icq_UDPSockRead(icq_UDPSok, &pak.head, sizeof(pak));
503 if(icqtohs(pak.head.cmd) == SRV_NEW_UIN)
505 icq_Uin = icqtohl(&pak.data[2]);
513 /************************
514 icq_UDPServMess functions
515 *************************/
516 BOOL
icq_GetServMess(icq_Link
*icqlink
, WORD num
)
518 return ((icqlink
->d
->icq_UDPServMess
[num
/8] & (1 << (num
%8))) >> (num
%8));
521 void icq_SetServMess(icq_Link
*icqlink
, WORD num
)
523 icqlink
->d
->icq_UDPServMess
[num
/8] |= (1 << (num
%8));
526 int icq_GetSok(icq_Link
*icqlink
)
528 return icqlink
->icq_UDPSok
;