1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
4 * $Id: tcp.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.
26 * Peer-to-peer ICQ protocol implementation
28 * Uses version 2 of the ICQ protocol
30 * Thanks to Douglas F. McLaughlin and many others for
31 * packet details (see tcp02.txt)
49 #include "stdpackets.h"
50 #include "chatsession.h"
51 #include "filesession.h"
54 Initializes structures necessary for TCP use. Not required by user
60 int icq_TCPInit(icq_Link
*icqlink
)
65 icqlink
->d
->icq_TCPLinks
=icq_ListNew();
66 icqlink
->d
->icq_ChatSessions
=icq_ListNew();
67 icqlink
->d
->icq_FileSessions
=icq_ListNew();
69 /* only the main listening socket gets created upon initialization -
70 * the other two are created when necessary */
71 plink
=icq_TCPLinkNew(icqlink
);
72 icq_TCPLinkListen(plink
);
73 icqlink
->icq_TCPSrvPort
=ntohs(plink
->socket_address
.sin_port
);
75 /* reset tcp sequence number */
76 icqlink
->d
->icq_TCPSequence
=0xfffffffe;
81 void icq_TCPDone(icq_Link
*icqlink
)
83 /* close and deallocate all tcp links, this will also close any attached
84 * file or chat sessions */
85 if (icqlink
->d
->icq_TCPLinks
) {
86 icq_ListDelete(icqlink
->d
->icq_TCPLinks
, icq_TCPLinkDelete
);
87 icqlink
->d
->icq_TCPLinks
= 0;
89 if (icqlink
->d
->icq_ChatSessions
) {
90 icq_ListDelete(icqlink
->d
->icq_ChatSessions
, icq_ChatSessionDelete
);
91 icqlink
->d
->icq_ChatSessions
= 0;
93 if (icqlink
->d
->icq_FileSessions
) {
94 icq_ListDelete(icqlink
->d
->icq_FileSessions
, icq_FileSessionDelete
);
95 icqlink
->d
->icq_FileSessions
= 0;
99 icq_TCPLink
*icq_TCPCheckLink(icq_Link
*icqlink
, DWORD uin
, int type
)
101 icq_TCPLink
*plink
=icq_FindTCPLink(icqlink
, uin
, type
);
105 plink
=icq_TCPLinkNew(icqlink
);
106 if(type
==TCP_LINK_MESSAGE
)
107 icq_TCPLinkConnect(plink
, uin
, 0);
113 DWORD
icq_TCPSendMessage(icq_Link
*icqlink
, DWORD uin
, const char *message
)
118 char data
[ICQ_MAX_MESSAGE_SIZE
] ;
120 strncpy(data
,message
,sizeof(data
)) ;
121 data
[sizeof(data
)-1]='\0';
122 icq_RusConv("kw", data
) ;
124 plink
=icq_TCPCheckLink(icqlink
, uin
, TCP_LINK_MESSAGE
);
126 /* create and send the message packet */
127 p
=icq_TCPCreateMessagePacket(plink
, data
);
128 sequence
=icq_TCPLinkSendSeq(plink
, p
, 0);
130 #ifdef TCP_PACKET_TRACE
131 printf("message packet sent to uin %lu { sequence=%lx }\n", uin
, p
->id
);
137 DWORD
icq_TCPSendURL(icq_Link
*icqlink
, DWORD uin
, const char *message
, const char *url
)
142 char data
[ICQ_MAX_MESSAGE_SIZE
];
144 plink
=icq_TCPCheckLink(icqlink
, uin
, TCP_LINK_MESSAGE
);
146 strncpy(data
, message
, sizeof(data
));
147 data
[sizeof(data
)-1] = '\0';
148 icq_RusConv("kw", data
);
150 /* create and send the url packet */
151 p
=icq_TCPCreateURLPacket(plink
, data
, url
);
152 sequence
=icq_TCPLinkSendSeq(plink
, p
, 0);
154 #ifdef TCP_PACKET_TRACE
155 printf("url packet queued for uin %lu { sequence=%lx }\n", uin
, p
->id
);
161 DWORD
icq_TCPSendAwayMessageReq(icq_Link
*icqlink
, DWORD uin
, int status
)
168 plink
=icq_TCPCheckLink(icqlink
, uin
, TCP_LINK_MESSAGE
);
170 /* create and send the message packet */
174 type
=ICQ_TCP_MSG_READAWAY
;
177 type
=ICQ_TCP_MSG_READDND
;
180 type
=ICQ_TCP_MSG_READNA
;
182 case STATUS_OCCUPIED
:
183 type
=ICQ_TCP_MSG_READOCCUPIED
;
185 case STATUS_FREE_CHAT
:
186 type
=ICQ_TCP_MSG_READFFC
;
189 type
=ICQ_TCP_MSG_READAWAY
;
192 p
=icq_TCPCreateAwayReqPacket(plink
, type
);
193 sequence
=icq_TCPLinkSendSeq(plink
, p
, 0);
195 #ifdef TCP_PACKET_TRACE
196 printf("away msg request packet sent to uin %lu { sequence=%lx }\n", uin
, p
->id
);
202 DWORD
icq_SendChatRequest(icq_Link
*icqlink
, DWORD uin
, const char *message
)
207 char data
[ICQ_MAX_MESSAGE_SIZE
];
209 plink
=icq_TCPCheckLink(icqlink
, uin
, TCP_LINK_MESSAGE
);
211 strncpy(data
, message
, sizeof(data
));
212 data
[sizeof(data
)-1] = '\0';
213 icq_RusConv("kw", data
);
215 /* create and send the url packet */
216 p
=icq_TCPCreateChatReqPacket(plink
, data
);
217 sequence
=icq_TCPLinkSendSeq(plink
, p
, 0);
219 #ifdef TCP_PACKET_TRACE
220 printf("chat req packet sent to uin %lu { sequence=%lx }\n", uin
, p
->id
);
226 unsigned long icq_SendFileRequest(icq_Link
*icqlink
, unsigned long uin
,
227 const char *message
, char **files
)
230 icq_FileSession
*pfile
;
232 unsigned long sequence
;
234 char data
[ICQ_MAX_MESSAGE_SIZE
];
235 char **filesiterator
;
236 char **pfilesiterator
;
238 plink
=icq_TCPCheckLink(icqlink
, uin
, TCP_LINK_MESSAGE
);
240 /* create the file session, this will be linked to the incoming icq_TCPLink
241 * in icq_HandleFileAck */
242 pfile
=icq_FileSessionNew(icqlink
);
243 pfile
->remote_uin
=uin
;
245 pfile
->direction
=FILE_STATUS_SENDING
;
247 /* count the number and size of the files */
248 pfile
->total_files
=0;
249 filesiterator
= files
;
250 while(*filesiterator
) {
252 struct _stat file_status
;
253 if(_stat(*filesiterator
, &file_status
)==0) {
255 struct stat file_status
;
256 if(stat(*filesiterator
, &file_status
)==0) {
258 pfile
->total_files
++;
259 pfile
->total_bytes
+=file_status
.st_size
;
264 pfile
->files
=(char **)malloc(sizeof(char *)*(pfile
->total_files
+1));
265 filesiterator
= files
;
266 pfilesiterator
= pfile
->files
;
267 while (*filesiterator
) {
268 *pfilesiterator
=(char *)malloc(strlen(*filesiterator
)+1);
269 strcpy(*pfilesiterator
,*filesiterator
);
273 *pfilesiterator
= NULL
;
275 strncpy(filename
, *(pfile
->files
), 64);
277 strncpy(data
, message
, sizeof(data
));
278 data
[sizeof(data
)-1]='\0';
279 icq_RusConv("kw", data
);
281 /* create and send the file req packet */
282 p
=icq_TCPCreateFileReqPacket(plink
, (char *)data
, filename
,
284 sequence
=icq_TCPLinkSendSeq(plink
, p
, 0);
287 #ifdef TCP_PACKET_TRACE
288 printf("file req packet sent to uin %lu { sequence=%lx }\n", uin
, p
->id
);
294 void icq_AcceptChatRequest(icq_Link
*icqlink
, DWORD uin
, unsigned long sequence
)
296 icq_TCPLink
*pmessage
, *plisten
;
297 icq_ChatSession
*pchat
;
300 pmessage
=icq_TCPCheckLink(icqlink
, uin
, TCP_LINK_MESSAGE
);
302 /* create the chat listening socket if necessary */
303 if(!(plisten
=icq_FindTCPLink(icqlink
, 0, TCP_LINK_CHAT
)))
305 plisten
=icq_TCPLinkNew(icqlink
);
306 plisten
->type
=TCP_LINK_CHAT
;
307 icq_TCPLinkListen(plisten
);
310 /* create the chat session, this will be linked to the incoming icq_TCPLink
311 * in TCPProcessHello */
312 pchat
=icq_ChatSessionNew(icqlink
);
314 pchat
->remote_uin
=uin
;
316 /* create and send the ack packet */
317 p
=icq_TCPCreateChatReqAck(pmessage
,
318 ntohs(plisten
->socket_address
.sin_port
));
319 (void)icq_TCPLinkSendSeq(pmessage
, p
, sequence
);
321 #ifdef TCP_PACKET_TRACE
322 printf("chat req ack sent to uin %lu { sequence=%lx }\n", uin
, sequence
);
326 void icq_TCPSendChatData(icq_Link
*icqlink
, DWORD uin
, const char *data
)
328 icq_TCPLink
*plink
=icq_FindTCPLink(icqlink
, uin
, TCP_LINK_CHAT
);
329 char data1
[ICQ_MAX_MESSAGE_SIZE
];
335 strncpy(data1
,data
,sizeof(data1
)) ;
336 data1
[sizeof(data1
)-1] = '\0';
337 data1_len
= strlen(data
);
338 icq_ChatRusConv_n("kw", data1
, data1_len
);
340 send(plink
->socket
, data1
, data1_len
, 0);
343 void icq_TCPSendChatData_n(icq_Link
*icqlink
, DWORD uin
, const char *data
, int len
)
345 icq_TCPLink
*plink
=icq_FindTCPLink(icqlink
, uin
, TCP_LINK_CHAT
);
351 data1
= (char *)malloc(len
);
352 memcpy(data1
, data
, len
);
353 icq_ChatRusConv_n("kw", data1
, len
);
355 send(plink
->socket
, data1
, len
, 0);
358 icq_FileSession
*icq_AcceptFileRequest(icq_Link
*icqlink
, DWORD uin
,
359 unsigned long sequence
)
361 icq_TCPLink
*pmessage
, *plisten
;
362 icq_FileSession
*pfile
;
365 pmessage
=icq_TCPCheckLink(icqlink
, uin
, TCP_LINK_MESSAGE
);
367 /* create the file listening socket if necessary */
368 if(!(plisten
=icq_FindTCPLink(icqlink
, 0, TCP_LINK_FILE
)))
370 plisten
=icq_TCPLinkNew(icqlink
);
371 plisten
->type
=TCP_LINK_FILE
;
372 icq_TCPLinkListen(plisten
);
375 /* create the file session, this will be linked to the incoming icq_TCPLink
376 * in TCPProcessHello */
377 pfile
=icq_FileSessionNew(icqlink
);
379 pfile
->remote_uin
=uin
;
380 pfile
->direction
=FILE_STATUS_RECEIVING
;
381 pfile
->tcplink
=plisten
;
382 icq_FileSessionSetStatus(pfile
, FILE_STATUS_LISTENING
);
384 /* create and send the ack packet */
385 p
=icq_TCPCreateFileReqAck(pmessage
,
386 ntohs(plisten
->socket_address
.sin_port
));
387 (void)icq_TCPLinkSendSeq(pmessage
, p
, sequence
);
389 #ifdef TCP_PACKET_TRACE
390 printf("file req ack sent to uin %lu { sequence=%lx }\n", uin
, sequence
);
396 void icq_RefuseFileRequest(icq_Link
*icqlink
, DWORD uin
,
397 unsigned long sequence
, const char *reason
)
399 icq_TCPLink
*pmessage
=icq_TCPCheckLink(icqlink
, uin
, TCP_LINK_MESSAGE
);
402 /* create and send the refuse packet */
403 p
=icq_TCPCreateFileReqRefuse(pmessage
,
404 ntohs(pmessage
->socket_address
.sin_port
), reason
);
405 (void)icq_TCPLinkSendSeq(pmessage
, p
, sequence
);
407 #ifdef TCP_PACKET_TRACE
408 printf("file req refuse sent to uin %lu { sequence=%lx, reason=\"%s\" }\n",
409 uin
, sequence
, reason
);
413 void icq_CancelFileRequest(icq_Link
*icqlink
, DWORD uin
, unsigned long sequence
)
415 icq_TCPLink
*pmessage
=icq_TCPCheckLink(icqlink
, uin
, TCP_LINK_MESSAGE
);
416 icq_FileSession
*psession
=icq_FindFileSession(icqlink
, uin
, sequence
);
420 icq_FileSessionClose(psession
);
422 /* create and send the cancel packet */
423 p
=icq_TCPCreateFileReqCancel(pmessage
,
424 ntohs(pmessage
->socket_address
.sin_port
));
425 (void)icq_TCPLinkSendSeq(pmessage
, p
, sequence
);
426 #ifdef TCP_PACKET_TRACE
427 printf("file req cancel sent to uin %lu { sequence=%lx }\n", uin
, sequence
);
431 void icq_RefuseChatRequest(icq_Link
*icqlink
, DWORD uin
,
432 unsigned long sequence
, const char *reason
)
434 icq_TCPLink
*pmessage
=icq_TCPCheckLink(icqlink
, uin
, TCP_LINK_MESSAGE
);
437 /* create and send the refuse packet */
438 p
=icq_TCPCreateChatReqRefuse(pmessage
,
439 ntohs(pmessage
->socket_address
.sin_port
), reason
);
440 (void)icq_TCPLinkSendSeq(pmessage
, p
, sequence
);
442 #ifdef TCP_PACKET_TRACE
443 printf("chat req refuse sent to uin %lu { sequence=%lx, reason=\"%s\" }\n",
444 uin
, sequence
, reason
);
448 void icq_CancelChatRequest(icq_Link
*icqlink
, DWORD uin
, unsigned long sequence
)
450 icq_TCPLink
*pmessage
=icq_TCPCheckLink(icqlink
, uin
, TCP_LINK_MESSAGE
);
451 icq_ChatSession
*psession
=icq_FindChatSession(icqlink
, uin
);
455 icq_ChatSessionClose(psession
);
457 /* create and send the cancel packet */
458 p
=icq_TCPCreateChatReqCancel(pmessage
,
459 ntohs(pmessage
->socket_address
.sin_port
));
460 (void)icq_TCPLinkSendSeq(pmessage
, p
, sequence
);
462 #ifdef TCP_PACKET_TRACE
463 printf("chat req cancel sent to uin %lu { sequence=%lx }\n", uin
, sequence
);