1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 1998-2014 Licq developers <licq-dev@googlegroups.com>
4 *
5 * Licq is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * Licq is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Licq; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "packet-tcp.h"
21
22 #include <boost/foreach.hpp>
23 #include <cstdio>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <fcntl.h>
29
30 #include <cerrno>
31
32 #include <licq/byteorder.h>
33 #include <licq/color.h>
34 #include <licq/contactlist/usermanager.h>
35 #include <licq/translator.h>
36 #include <licq/logging/log.h>
37 #include <licq/version.h>
38
39 #include "buffer.h"
40 #include "defines.h"
41 #include "gettext.h"
42 #include "icq.h"
43 #include "socket.h"
44 #include "owner.h"
45 #include "user.h"
46
47 using namespace LicqIcq;
48 using Licq::UserId;
49 using Licq::gLog;
50 using Licq::gTranslator;
51 using std::list;
52 using std::string;
53
54 //=====TCP===================================================================
55 static unsigned char client_check_data[] = {
56 "As part of this software beta version Mirabilis is "
57 "granting a limited access to the ICQ network, "
58 "servers, directories, listings, information and databases (\""
59 "ICQ Services and Information\"). The "
60 "ICQ Service and Information may databases (\""
61 "ICQ Services and Information\"). The "
62 "ICQ Service and Information may\0"
63 };
64
65
66 #define DEBUG_ENCRYPTION(x)
67 //#define DEBUG_ENCRYPTION(x) fprintf(stderr, x)
68
Encrypt_Client(CBuffer * pkt,unsigned long version)69 void LicqIcq::Encrypt_Client(CBuffer* pkt, unsigned long version)
70 {
71 unsigned long B1, M1, check;
72 unsigned int i;
73 unsigned char X1, X2, X3;
74 unsigned char* buf = (unsigned char*)pkt->getDataStart() + 2;
75 unsigned char bak[6];
76 unsigned long offset;
77 unsigned long size = pkt->getDataSize() - 2;
78
79 if (version < 4)
80 return; // no encryption necessary.
81
82 switch(version)
83 {
84 case 4:
85 case 5:
86 offset = 6;
87 break;
88 case 7:
89 case 8:
90 case 6:
91 default:
92 offset = 0;
93 }
94
95 pkt->log(Licq::Log::Debug, tr("Unencrypted (ICQ) TCP Packet (%lu bytes)"), size);
96
97 // Fuck AOL
98 if (version > 6)
99 {
100 buf += 1;
101 size -= 1;
102 }
103
104 // calculate verification data
105 M1 = (rand() % ((size < 255 ? size : 255)-10))+10;
106 X1 = buf[M1] ^ 0xFF;
107 X2 = rand() % 220;
108 X3 = client_check_data[X2] ^ 0xFF;
109 if(offset) {
110 for(i=0;i<6;i++) bak[i] = buf[i];
111 B1 = (buf[offset+4]<<24)|(buf[offset+6]<<16)|(buf[2]<<8)|buf[0];
112 }
113 else
114 B1 = (buf[4]<<24)|(buf[6]<<16)|(buf[4]<<8)|(buf[6]);
115
116 // calculate checkcode
117 check = (M1 << 24) | (X1 << 16) | (X2 << 8) | X3;
118 check ^= B1;
119 DEBUG_ENCRYPTION(("complete check %08lx\n", check));
120
121 // main XOR key
122 unsigned long key = 0x67657268 * size + check;
123
124 // XORing the actual data
125 for(i=0;i<(size+3)/4;i+=4){
126 unsigned long hex = key + client_check_data[i&0xFF];
127 buf[i+0] ^= hex&0xFF;buf[i+1] ^= (hex>>8)&0xFF;
128 buf[i+2] ^= (hex>>16)&0xFF;buf[i+3] ^= (hex>>24)&0xFF;
129 }
130
131 // in TCPv4 are the first 6 bytes unencrypted
132 // so restore them
133 if(offset) for(i=0;i<6;i++) buf[i] = bak[i];
134
135 // storing the checkcode
136 buf[offset+3] = (check>>24)&0xFF;
137 buf[offset+2] = (check>>16)&0xFF;
138 buf[offset+1] = (check>>8)&0xFF;
139 buf[offset+0] = check&0xFF;
140 }
141
142
Decrypt_Client(CBuffer * pkt,unsigned long version)143 bool LicqIcq::Decrypt_Client(CBuffer* pkt, unsigned long version)
144 {
145 unsigned long hex, key, B1, M1, check;
146 unsigned int i;
147 unsigned char X1, X2, X3;
148 unsigned char* buf = (unsigned char*)pkt->getDataStart() + 2;
149 unsigned char bak[6];
150 unsigned long size = pkt->getDataSize() - 2;
151 unsigned long offset;
152
153 if(version < 4)
154 return true; // no decryption necessary.
155
156 switch(version){
157 case 4:
158 case 5:
159 offset = 6;
160 break;
161 case 7:
162 case 8:
163 case 6:
164 default:
165 offset = 0;
166 }
167
168 // Fuck AOL
169 if (version > 6)
170 {
171 buf += 1;
172 size -= 1;
173 }
174
175 // backup the first 6 bytes
176 if(offset)
177 for(i=0;i<6;i++) bak[i] = buf[i];
178
179 // retrieve checkcode
180 check = (buf[offset+3]<<24)|(buf[offset+2]<<16)|(buf[offset+1]<<8)|(buf[offset+0]);
181
182 DEBUG_ENCRYPTION(("size %d, check %08lx\n", size, check));
183
184 // main XOR key
185 key = 0x67657268 * size + check;
186
187 for(i=4; i<(size+3)/4; i+=4) {
188 hex = key + client_check_data[i&0xFF];
189 buf[i+0] ^= hex&0xFF;buf[i+1] ^= (hex>>8)&0xFF;
190 buf[i+2] ^= (hex>>16)&0xFF;buf[i+3] ^= (hex>>24)&0xFF;
191 }
192
193 // retrive validate data
194 if(offset) {
195 // in TCPv4 are the first 6 bytes unencrypted
196 // so restore them
197 for(i=0;i<6;i++) buf[i] = bak[i];
198 B1 = (buf[offset+4]<<24)|(buf[offset+6]<<16)|(buf[2]<<8)|buf[0];
199 }
200 else
201 B1 = (buf[4]<<24) | (buf[6]<<16) | (buf[4]<<8) | (buf[6]<<0);
202
203 // special decryption
204 B1 ^= check;
205
206 // validate packet
207 M1 = (B1 >> 24) & 0xFF;
208 if(M1 < 10 || M1 >= size) {
209 DEBUG_ENCRYPTION(("range check failed, M1 is %02x, returning false\n", M1));
210 return false;
211 }
212
213 X1 = buf[M1] ^ 0xFF;
214 if(((B1 >> 16) & 0xFF) != X1) {
215 DEBUG_ENCRYPTION(("M1 is %02x\n", M1));
216 DEBUG_ENCRYPTION(("calculated X1 (%02lx) != %02x\n", X1, (B1 >> 16) & 0xFF));
217 return false;
218 }
219
220 X2 = ((B1 >> 8) & 0xFF);
221 if(X2 < 220) {
222 X3 = client_check_data[X2] ^ 0xFF;
223 if((B1 & 0xFF) != X3) {
224 DEBUG_ENCRYPTION(("calculated X3 (%02x) does not match B1 (%02x)\n", X3, B1 & 0xFF));
225 return false;
226 }
227 }
228
229 pkt->log(Licq::Log::Debug, tr("Decrypted (ICQ) TCP Packet (%lu bytes)"), size);
230
231 return true;
232 }
233
CPacketTcp_Handshake()234 CPacketTcp_Handshake::CPacketTcp_Handshake()
235 : buffer(NULL)
236 {
237 // Empty
238 }
239
~CPacketTcp_Handshake()240 CPacketTcp_Handshake::~CPacketTcp_Handshake()
241 {
242 delete buffer;
243 }
244
CPacketTcp_Handshake_v2(unsigned long nLocalPort)245 CPacketTcp_Handshake_v2::CPacketTcp_Handshake_v2(unsigned long nLocalPort)
246 {
247 m_nLocalPort = nLocalPort;
248
249 m_nSize = 28;
250 buffer = new CBuffer(m_nSize);
251 buffer->packUInt16LE(m_nSize-2); // Packet length
252
253 buffer->PackChar(ICQ_CMDxTCP_HANDSHAKE);
254 buffer->PackUnsignedLong(ICQ_VERSION_TCP);
255 buffer->PackUnsignedLong(m_nLocalPort);
256 buffer->PackUnsignedLong(gIcqProtocol.icqOwnerUin());
257 buffer->PackUnsignedLong(s_nLocalIp);
258 buffer->PackUnsignedLong(s_nRealIp);
259 buffer->PackChar(gIcqProtocol.directMode() ? MODE_DIRECT : MODE_INDIRECT);
260 buffer->PackUnsignedLong(m_nLocalPort);
261 }
262
263
CPacketTcp_Handshake_v4(unsigned long nLocalPort)264 CPacketTcp_Handshake_v4::CPacketTcp_Handshake_v4(unsigned long nLocalPort)
265 {
266 m_nLocalPort = nLocalPort;
267
268 m_nSize = 28;
269 buffer = new CBuffer(m_nSize);
270 buffer->packUInt16LE(m_nSize-2); // Packet length
271
272 buffer->PackChar(ICQ_CMDxTCP_HANDSHAKE);
273 buffer->PackUnsignedLong(ICQ_VERSION_TCP);
274 buffer->PackUnsignedLong(0x00000000);
275 buffer->PackUnsignedLong(gIcqProtocol.icqOwnerUin());
276 buffer->PackUnsignedLong(s_nLocalIp); // maybe should be 0
277 buffer->PackUnsignedLong(s_nRealIp);
278 buffer->PackChar(gIcqProtocol.directMode() ? MODE_DIRECT : MODE_INDIRECT);
279 buffer->PackUnsignedLong(m_nLocalPort);
280 }
281
282
283 //=====PacketTcp_Handshake======================================================
CPacketTcp_Handshake_v6(unsigned long nDestinationUin,unsigned long,unsigned short nLocalPort)284 CPacketTcp_Handshake_v6::CPacketTcp_Handshake_v6(unsigned long nDestinationUin,
285 unsigned long /* nSessionId */, unsigned short nLocalPort)
286 {
287 m_nDestinationUin = nDestinationUin;
288
289 m_nSize = 46;
290 buffer = new CBuffer(m_nSize);
291 buffer->packUInt16LE(m_nSize-2); // Packet length
292
293 buffer->PackChar(ICQ_CMDxTCP_HANDSHAKE);
294 buffer->PackUnsignedShort(ICQ_VERSION_TCP);
295 buffer->PackUnsignedShort(0x0027); //size
296 buffer->PackUnsignedLong(m_nDestinationUin);
297 buffer->PackUnsignedShort(0);
298 buffer->PackUnsignedLong(nLocalPort);
299 buffer->PackUnsignedLong(gIcqProtocol.icqOwnerUin());
300 buffer->PackUnsignedLong(s_nLocalIp);
301 buffer->PackUnsignedLong(s_nRealIp);
302 buffer->PackChar(gIcqProtocol.directMode() ? MODE_DIRECT : MODE_INDIRECT);
303 buffer->PackUnsignedLong(nLocalPort == 0 ? s_nLocalPort : nLocalPort);
304
305 char id[16];
306 snprintf(id, 16, "%lu", nDestinationUin);
307 UserId userId(gIcqProtocol.ownerId(), id);
308 UserReadGuard u(userId);
309 if (u.isLocked())
310 {
311 buffer->PackUnsignedLong(u->Cookie());
312 m_nSessionId = u->Cookie();
313 }
314 else
315 {
316 m_nSessionId = 0;
317 buffer->PackUnsignedLong(0);
318 }
319
320 buffer->PackUnsignedLong(0x00000050); // constant
321 buffer->PackUnsignedLong(0x00000003); // constant
322 }
323
324
CPacketTcp_Handshake_v6(CBuffer * inbuf)325 CPacketTcp_Handshake_v6::CPacketTcp_Handshake_v6(CBuffer *inbuf)
326 {
327 inbuf->unpackUInt16LE(); // Packet length
328 m_nHandshake = inbuf->UnpackChar();
329 m_nVersionMajor = inbuf->UnpackUnsignedShort();
330 m_nVersionMinor = inbuf->UnpackUnsignedShort();
331 m_nDestinationUin = inbuf->UnpackUnsignedLong();
332 inbuf->UnpackUnsignedLong();
333 inbuf->UnpackUnsignedShort();
334 m_nSourceUin = inbuf->UnpackUnsignedLong();
335 m_nLocalIp = inbuf->UnpackUnsignedLong();
336 m_nRealIp = inbuf->UnpackUnsignedLong();
337 m_nMode = inbuf->UnpackChar();
338 inbuf->UnpackUnsignedLong(); // port of some kind...?
339 m_nSessionId = inbuf->UnpackUnsignedLong();
340 //inbuf->UnpackUnsignedLong(); // constant
341 //inbuf->UnpackUnsignedLong(); // constant
342 }
343
344
CPacketTcp_Handshake_v7(unsigned long nDestinationUin,unsigned long,unsigned short nLocalPort,unsigned long nId)345 CPacketTcp_Handshake_v7::CPacketTcp_Handshake_v7(unsigned long nDestinationUin,
346 unsigned long /* nSessionId */, unsigned short nLocalPort, unsigned long nId)
347 {
348 m_nDestinationUin = nDestinationUin;
349
350 m_nSize = 50;
351 buffer = new CBuffer(m_nSize);
352 buffer->packUInt16LE(m_nSize-2); // Packet length
353
354 buffer->PackChar(ICQ_CMDxTCP_HANDSHAKE);
355 buffer->PackUnsignedShort(ICQ_VERSION_TCP);
356 buffer->PackUnsignedShort(0x002b); // size
357 buffer->PackUnsignedLong(m_nDestinationUin);
358 buffer->PackUnsignedShort(0);
359 buffer->PackUnsignedLong(nLocalPort == 0 ? s_nLocalPort : nLocalPort);
360 buffer->PackUnsignedLong(gIcqProtocol.icqOwnerUin());
361 buffer->PackUnsignedLong(s_nRealIp);
362 buffer->PackUnsignedLong(s_nLocalIp);
363 buffer->PackChar(gIcqProtocol.directMode() ? MODE_DIRECT : MODE_INDIRECT);
364 buffer->PackUnsignedLong(nLocalPort == 0 ? s_nLocalPort : nLocalPort);
365
366 char id[16];
367 snprintf(id, 16, "%lu", nDestinationUin);
368 UserId userId(gIcqProtocol.ownerId(), id);
369 UserReadGuard u(userId);
370 if (u.isLocked())
371 {
372 buffer->PackUnsignedLong(u->Cookie());
373 m_nSessionId = u->Cookie();
374 }
375 else
376 {
377 m_nSessionId = 0;
378 buffer->PackUnsignedLong(0);
379 }
380
381 buffer->PackUnsignedLong(0x00000050); // constant
382 buffer->PackUnsignedLong(0x00000003); // constant
383 buffer->PackUnsignedLong(nId); // the connection id for reverse connect
384
385 }
386
387
CPacketTcp_Handshake_v7(CBuffer * inbuf)388 CPacketTcp_Handshake_v7::CPacketTcp_Handshake_v7(CBuffer *inbuf)
389 {
390 inbuf->unpackUInt16LE(); // Packet length
391 m_nHandshake = inbuf->UnpackChar();
392 m_nVersionMajor = inbuf->UnpackUnsignedShort();
393 inbuf->UnpackUnsignedShort(); // Length
394 m_nDestinationUin = inbuf->UnpackUnsignedLong();
395 inbuf->UnpackUnsignedShort();
396 inbuf->UnpackUnsignedLong();
397 m_nSourceUin = inbuf->UnpackUnsignedLong();
398 m_nRealIp = inbuf->UnpackUnsignedLong();
399 m_nLocalIp = inbuf->UnpackUnsignedLong();
400 m_nMode = inbuf->UnpackChar();
401 inbuf->UnpackUnsignedLong();
402 m_nSessionId = inbuf->UnpackUnsignedLong(); // Mmmm cookie
403 inbuf->incDataPosRead(8);
404 m_nId = inbuf->UnpackUnsignedLong();
405 }
406
407
CPacketTcp_Handshake_Ack()408 CPacketTcp_Handshake_Ack::CPacketTcp_Handshake_Ack()
409 {
410 m_nSize = 6;
411 buffer = new CBuffer(m_nSize);
412 buffer->packUInt16LE(m_nSize-2); // Packet length
413
414 buffer->PackUnsignedLong(1);
415 }
416
CPacketTcp_Handshake_Confirm(int channel,unsigned short nSequence)417 CPacketTcp_Handshake_Confirm::CPacketTcp_Handshake_Confirm(int channel,
418 unsigned short nSequence)
419 : myChannel(channel)
420 {
421 m_nSize = 35;
422 buffer = new CBuffer(m_nSize);
423 buffer->packUInt16LE(m_nSize-2); // Packet length
424
425 const uint8_t* GUID;
426 unsigned long nOurId;
427 switch (channel)
428 {
429 case DcSocket::ChannelNormal:
430 nOurId = 0x00000001;
431 GUID = PLUGIN_NORMAL;
432 break;
433 case DcSocket::ChannelInfo:
434 nOurId = 0x000003EB;
435 GUID = PLUGIN_INFOxMANAGER;
436 break;
437 case DcSocket::ChannelStatus:
438 nOurId = 0x000003EA;
439 GUID = PLUGIN_STATUSxMANAGER;
440 break;
441 default:
442 gLog.warning(tr("Channel %u is not implemented"), channel);
443 return;
444 }
445
446 buffer->PackChar(0x03);
447 buffer->PackUnsignedLong(0x0000000A);
448 buffer->PackUnsignedLong(nOurId);
449 buffer->PackUnsignedLong(nSequence);
450 if (nSequence == 0) //we are initiating the connection
451 {
452 buffer->Pack(GUID, 16);
453 buffer->PackUnsignedLong(0x00040001);
454 }
455 else
456 {
457 buffer->Pack(GUID, 8);
458 buffer->PackUnsignedLong(0x00040001);
459 buffer->Pack(GUID + 8, 8);
460 }
461 }
462
CPacketTcp_Handshake_Confirm(CBuffer * inbuf)463 CPacketTcp_Handshake_Confirm::CPacketTcp_Handshake_Confirm(CBuffer *inbuf)
464 {
465 inbuf->incDataPosRead(5); //skip over junk
466 m_nId = inbuf->UnpackUnsignedLong(); // some sort of id??
467 inbuf->UnpackUnsignedLong(); // 0 in incomming, our id in outgoing
468
469 char GUID[16];
470 for (int i = 0; i < 16; i ++)
471 (*inbuf) >> GUID[i];
472
473 if (memcmp(GUID, PLUGIN_NORMAL, 16) == 0)
474 myChannel = DcSocket::ChannelNormal;
475 else if (memcmp(GUID, PLUGIN_INFOxMANAGER, 16) == 0)
476 myChannel = DcSocket::ChannelInfo;
477 else if (memcmp(GUID, PLUGIN_STATUSxMANAGER, 16) == 0)
478 myChannel = DcSocket::ChannelStatus;
479 else
480 {
481 gLog.warning(tr("Unknown channel GUID."));
482 myChannel = DcSocket::ChannelUnknown;
483 }
484 }
485
486 //=====PacketTcp================================================================
Finalize(Licq::INetSocket * s)487 Licq::Buffer* CPacketTcp::Finalize(Licq::INetSocket *s)
488 {
489 // Set the local port in the tcp packet now
490 if (s != NULL && LocalPortOffset() != NULL)
491 {
492 LocalPortOffset()[0] = s->getLocalPort() & 0xFF;
493 LocalPortOffset()[1] = (s->getLocalPort() >> 8) & 0xFF;
494 }
495
496 Encrypt_Client(buffer, m_nVersion);
497 return buffer;
498 }
499
CPacketTcp(unsigned long _nCommand,unsigned short _nSubCommand,int channel,const string & message,bool _bAccept,unsigned short nLevel,User * user)500 CPacketTcp::CPacketTcp(unsigned long _nCommand, unsigned short _nSubCommand, int channel,
501 const string& message, bool _bAccept, unsigned short nLevel, User* user)
502 : myChannel(channel)
503 {
504 // Setup the message type and status fields using our online status
505 Licq::OwnerReadGuard o(gIcqProtocol.ownerId());
506 unsigned short s;
507 if (user->statusToUser() != Licq::User::OfflineStatus)
508 s = IcqProtocol::icqStatusFromStatus(user->statusToUser());
509 else
510 s = IcqProtocol::icqStatusFromStatus(o->status());
511 m_nLevel = nLevel;
512 m_nVersion = user->ConnectionVersion();
513 if (m_nVersion >= 7)
514 {
515 if (nLevel & ICQ_TCPxMSG_URGENT)
516 {
517 nLevel &= ~ICQ_TCPxMSG_URGENT;
518 nLevel |= ICQ_TCPxMSG_URGENT2;
519 }
520 else if (nLevel & ICQ_TCPxMSG_LIST)
521 {
522 nLevel &= ~ICQ_TCPxMSG_LIST;
523 nLevel |= ICQ_TCPxMSG_LIST2;
524 }
525 }
526
527 switch(_nCommand)
528 {
529 case ICQ_CMDxTCP_CANCEL:
530 case ICQ_CMDxTCP_START:
531 {
532 m_nStatus = 0;
533 m_nMsgType = nLevel;
534 if (m_nVersion >= 7)
535 {
536 m_nStatus = s;
537 break;
538 }
539
540 switch (s)
541 {
542 case ICQ_STATUS_AWAY: m_nMsgType |= ICQ_TCPxMSG_FxAWAY; break;
543 case ICQ_STATUS_NA: m_nMsgType |= ICQ_TCPxMSG_FxNA; break;
544 case ICQ_STATUS_DND: m_nMsgType |= ICQ_TCPxMSG_FxDND; break;
545 case ICQ_STATUS_OCCUPIED: m_nMsgType |= ICQ_TCPxMSG_FxOCCUPIED; break;
546 case ICQ_STATUS_ONLINE:
547 case ICQ_STATUS_FREEFORCHAT:
548 default: m_nMsgType |= ICQ_TCPxMSG_FxONLINE; break;
549 }
550 if (o->isInvisible())
551 m_nMsgType |= ICQ_TCPxMSG_FxINVISIBLE;
552 break;
553 }
554
555 case ICQ_CMDxTCP_ACK:
556 {
557 m_nMsgType = ICQ_TCPxMSG_AUTOxREPLY;
558 if (!_bAccept)
559 m_nStatus = ICQ_TCPxACK_REFUSE;
560 // If we are accepting a chat or file request then always say we are online
561 else if (nLevel == ICQ_TCPxMSG_URGENT ||
562 nLevel == ICQ_TCPxMSG_URGENT2 ||
563 _nSubCommand == ICQ_CMDxSUB_CHAT ||
564 _nSubCommand == ICQ_CMDxSUB_FILE)
565 m_nStatus = ICQ_TCPxACK_ONLINE;
566 else
567 {
568 switch (s)
569 {
570 case ICQ_STATUS_AWAY: m_nStatus = ICQ_TCPxACK_AWAY; break;
571 case ICQ_STATUS_NA: m_nStatus = ICQ_TCPxACK_NA; break;
572 case ICQ_STATUS_DND:
573 m_nStatus = (!user->customAutoResponse().empty() && _nSubCommand == ICQ_CMDxTCP_READxDNDxMSG)
574 ? ICQ_TCPxACK_DNDxCAR : ICQ_TCPxACK_DND;
575 break;
576 case ICQ_STATUS_OCCUPIED:
577 m_nStatus = (!user->customAutoResponse().empty() && _nSubCommand == ICQ_CMDxTCP_READxOCCUPIEDxMSG)
578 ? ICQ_TCPxACK_OCCUPIEDxCAR : ICQ_TCPxACK_OCCUPIED;
579 break;
580 case ICQ_STATUS_ONLINE:
581 case ICQ_STATUS_FREEFORCHAT:
582 default: m_nStatus = ICQ_TCPxACK_ONLINE; break;
583 }
584 }
585 break;
586 }
587 }
588 o.unlock();
589
590 m_nSourceUin = gIcqProtocol.icqOwnerUin();
591 m_nCommand = _nCommand;
592 m_nSubCommand = _nSubCommand;
593 myMessage = message;
594 m_nLocalPort = user->LocalPort();
595
596 // don't increment the sequence if this is an ack and cancel packet
597 if (m_nCommand == ICQ_CMDxTCP_START) m_nSequence = user->Sequence(true);
598
599 // Buffer and size are set by InitBuffer
600 m_nSize = 0;
601 buffer = NULL;
602 }
603
~CPacketTcp()604 CPacketTcp::~CPacketTcp()
605 {
606 delete buffer;
607 }
608
609
InitBuffer()610 void CPacketTcp::InitBuffer()
611 {
612 switch (m_nVersion)
613 {
614 case 6:
615 InitBuffer_v6();
616 break;
617 case 4:
618 case 5:
619 InitBuffer_v4();
620 break;
621 case 2:
622 case 3:
623 InitBuffer_v2();
624 break;
625 case 7:
626 case 8:
627 default:
628 InitBuffer_v7();
629 break;
630 }
631 }
632
PostBuffer()633 void CPacketTcp::PostBuffer()
634 {
635 switch (m_nVersion)
636 {
637 case 7:
638 case 8:
639 PostBuffer_v7();
640 break;
641 case 6:
642 PostBuffer_v6();
643 break;
644 case 4:
645 case 5:
646 PostBuffer_v4();
647 break;
648 case 2:
649 case 3:
650 PostBuffer_v2();
651 break;
652 }
653
654 if (buffer->getDataSize() != m_nSize)
655 {
656 gLog.warning(tr("Packet length (%lu) different than expected (%i)"),
657 buffer->getDataSize(), m_nSize);
658 *((uint16_t*)buffer->getDataStart()) = LE_16(buffer->getDataSize() - 2);
659 }
660 }
661
662
InitBuffer_v2()663 void CPacketTcp::InitBuffer_v2()
664 {
665 m_nSize += 35 + myMessage.size() + 4;
666 if (m_nVersion != 2)
667 m_nSize += 3;
668 buffer = new CBuffer(m_nSize);
669 buffer->packUInt16LE(m_nSize-2); // Packet length
670
671 buffer->PackUnsignedLong(m_nSourceUin);
672 buffer->PackUnsignedShort(m_nVersion == 2 ? 2 : ICQ_VERSION_TCP);
673 buffer->PackUnsignedLong(m_nCommand);
674 buffer->PackUnsignedLong(m_nSourceUin);
675 buffer->PackUnsignedShort(m_nSubCommand);
676 buffer->pack(myMessage);
677 buffer->PackUnsignedLong(s_nLocalIp);
678 buffer->PackUnsignedLong(s_nRealIp);
679 m_szLocalPortOffset = buffer->getDataPosWrite();
680 buffer->PackUnsignedLong(m_nLocalPort);
681 buffer->PackChar(gIcqProtocol.directMode() ? MODE_DIRECT : MODE_INDIRECT);
682 buffer->PackUnsignedShort(m_nStatus);
683 buffer->PackUnsignedShort(m_nMsgType);
684 }
685
PostBuffer_v2()686 void CPacketTcp::PostBuffer_v2()
687 {
688 buffer->PackUnsignedLong(m_nSequence);
689 // several V2 clients don't like our extension, so we omit it for them
690 if (m_nVersion != 2)
691 {
692 buffer->PackChar('L');
693 buffer->PackUnsignedShort(LICQ_VERSION);
694 }
695 }
696
697
InitBuffer_v4()698 void CPacketTcp::InitBuffer_v4()
699 {
700 m_nSize += 39 + myMessage.size() + 7;
701 buffer = new CBuffer(m_nSize);
702 buffer->packUInt16LE(m_nSize-2); // Packet length
703
704 buffer->PackUnsignedLong(m_nSourceUin);
705 buffer->PackUnsignedShort(ICQ_VERSION_TCP);
706 buffer->PackUnsignedLong(0x00000000); // Checksum
707 buffer->PackUnsignedLong(m_nCommand);
708 buffer->PackUnsignedLong(m_nSourceUin);
709 buffer->PackUnsignedShort(m_nSubCommand);
710 buffer->pack(myMessage);
711 buffer->PackUnsignedLong(s_nLocalIp);
712 buffer->PackUnsignedLong(s_nRealIp);
713 m_szLocalPortOffset = buffer->getDataPosWrite();
714 buffer->PackUnsignedLong(m_nLocalPort);
715 buffer->PackChar(gIcqProtocol.directMode() ? MODE_DIRECT : MODE_INDIRECT);
716 buffer->PackUnsignedShort(m_nStatus);
717 buffer->PackUnsignedShort(m_nMsgType);
718 }
719
PostBuffer_v4()720 void CPacketTcp::PostBuffer_v4()
721 {
722 buffer->PackUnsignedLong(m_nSequence);
723 buffer->PackChar('L');
724 buffer->PackUnsignedShort(LICQ_VERSION);
725 }
726
727
InitBuffer_v6()728 void CPacketTcp::InitBuffer_v6()
729 {
730 m_nSize += 32 + myMessage.size() + 0;
731 buffer = new CBuffer(m_nSize);
732 buffer->packUInt16LE(m_nSize-2); // Packet length
733
734 buffer->PackUnsignedLong(0); // Checksum
735 buffer->PackUnsignedShort(m_nCommand);
736 buffer->PackUnsignedShort(0x000E); //???
737 buffer->PackUnsignedShort(m_nSequence);
738 buffer->PackUnsignedLong(0); // Always zero, probably decryption validation
739 buffer->PackUnsignedLong(0); // ""
740 buffer->PackUnsignedLong(0); // ""
741 buffer->PackUnsignedShort(m_nSubCommand);
742 buffer->PackUnsignedShort(m_nStatus);
743 buffer->PackUnsignedShort(m_nMsgType);
744 buffer->PackUnsignedShort(myMessage.size());
745 buffer->pack(myMessage);
746
747 m_szLocalPortOffset = NULL;
748 }
749
PostBuffer_v6()750 void CPacketTcp::PostBuffer_v6()
751 {
752 // don't break ICQ2000
753 // buffer->PackChar('L');
754 // buffer->PackUnsignedShort(LICQ_VERSION);
755 }
756
InitBuffer_v7()757 void CPacketTcp::InitBuffer_v7()
758 {
759 m_nSize += 31;
760 if (channel() == DcSocket::ChannelNormal)
761 m_nSize += 2 + myMessage.size();
762 else
763 m_nSize += 3;
764 buffer = new CBuffer(m_nSize);
765 buffer->packUInt16LE(m_nSize-2); // Packet length
766
767 buffer->PackChar(0x02);
768 buffer->PackUnsignedLong(0); // Checksum
769 buffer->PackUnsignedShort(m_nCommand);
770 buffer->PackUnsignedShort((channel() == DcSocket::ChannelNormal) ? 0x000E : 0x0012);
771 buffer->PackUnsignedShort(m_nSequence);
772 buffer->PackUnsignedLong(0);
773 buffer->PackUnsignedLong(0);
774 buffer->PackUnsignedLong(0);
775 buffer->PackUnsignedShort(m_nSubCommand);
776 buffer->PackUnsignedShort(m_nStatus);
777 buffer->PackUnsignedShort((channel() == DcSocket::ChannelNormal) ? m_nMsgType : m_nLevel);
778
779 if (channel() == DcSocket::ChannelNormal)
780 {
781 buffer->PackUnsignedShort(myMessage.size());
782 buffer->pack(myMessage);
783 }
784 else
785 {
786 buffer->PackUnsignedShort(1);
787 buffer->PackChar(myMessage[0]);
788 }
789
790 m_szLocalPortOffset = NULL;
791 }
792
PostBuffer_v7()793 void CPacketTcp::PostBuffer_v7()
794 {
795 }
796
797
798 //-----Message------------------------------------------------------------------
CPT_Message(const string & message,unsigned short nLevel,bool bMR,const Licq::Color * pColor,User * pUser,bool isUtf8)799 CPT_Message::CPT_Message(const string& message, unsigned short nLevel, bool bMR,
800 const Licq::Color* pColor, User* pUser, bool isUtf8)
801 : CPacketTcp(ICQ_CMDxTCP_START,
802 ICQ_CMDxSUB_MSG | (bMR ? ICQ_CMDxSUB_FxMULTIREC : 0),
803 DcSocket::ChannelNormal,
804 message, true, nLevel, pUser)
805 {
806 if (m_nVersion >= 6)
807 {
808 m_nSize += 8;
809 if (isUtf8)
810 m_nSize += 4 + sizeof(ICQ_CAPABILITY_UTF8_STR)-1;
811 }
812 InitBuffer();
813 if (m_nVersion >= 6)
814 {
815 if (pColor == NULL)
816 {
817 buffer->PackUnsignedLong(0x00000000);
818 buffer->PackUnsignedLong(0x00FFFFFF);
819 }
820 else
821 {
822 buffer->PackUnsignedLong(pColor->foreground());
823 buffer->PackUnsignedLong(pColor->background());
824 }
825
826 if (isUtf8)
827 {
828 buffer->PackUnsignedLong(sizeof(ICQ_CAPABILITY_UTF8_STR)-1);
829 buffer->Pack(ICQ_CAPABILITY_UTF8_STR, sizeof(ICQ_CAPABILITY_UTF8_STR)-1);
830 }
831 }
832 PostBuffer();
833 }
834
835 //-----Url----------------------------------------------------------------------
CPT_Url(const string & message,unsigned short nLevel,bool bMR,const Licq::Color * pColor,User * pUser)836 CPT_Url::CPT_Url(const string& message, unsigned short nLevel, bool bMR,
837 const Licq::Color* pColor, User* pUser)
838 : CPacketTcp(ICQ_CMDxTCP_START,
839 ICQ_CMDxSUB_URL | (bMR ? ICQ_CMDxSUB_FxMULTIREC : 0),
840 DcSocket::ChannelNormal,
841 message, true, nLevel, pUser)
842 {
843 if (m_nVersion >= 6)
844 m_nSize += 8;
845 InitBuffer();
846 if (m_nVersion >= 6)
847 {
848 if (pColor == NULL)
849 {
850 buffer->PackUnsignedLong(0x00000000);
851 buffer->PackUnsignedLong(0x00FFFFFF);
852 }
853 else
854 {
855 buffer->PackUnsignedLong(pColor->foreground());
856 buffer->PackUnsignedLong(pColor->background());
857 }
858 }
859 PostBuffer();
860 }
861
862
863 //-----ContactList-----------------------------------------------------------
CPT_ContactList(const string & message,unsigned short nLevel,bool bMR,const Licq::Color * pColor,User * pUser)864 CPT_ContactList::CPT_ContactList(const string& message, unsigned short nLevel, bool bMR,
865 const Licq::Color* pColor, User* pUser)
866 : CPacketTcp(ICQ_CMDxTCP_START,
867 ICQ_CMDxSUB_CONTACTxLIST | (bMR ? ICQ_CMDxSUB_FxMULTIREC : 0),
868 DcSocket::ChannelNormal,
869 message, true, nLevel, pUser)
870 {
871 if (m_nVersion >= 6)
872 m_nSize += 8;
873 InitBuffer();
874 if (m_nVersion >= 6)
875 {
876 if (pColor == NULL)
877 {
878 buffer->PackUnsignedLong(0x00000000);
879 buffer->PackUnsignedLong(0x00FFFFFF);
880 }
881 else
882 {
883 buffer->PackUnsignedLong(pColor->foreground());
884 buffer->PackUnsignedLong(pColor->background());
885 }
886 }
887 PostBuffer();
888 }
889
890
891 //-----ReadAwayMessage----------------------------------------------------------
CPT_ReadAwayMessage(User * _cUser)892 CPT_ReadAwayMessage::CPT_ReadAwayMessage(User* _cUser)
893 : CPacketTcp(ICQ_CMDxTCP_START, ICQ_CMDxTCP_READxAWAYxMSG,
894 DcSocket::ChannelNormal, "", true, ICQ_TCPxMSG_AUTOxREPLY, _cUser)
895 {
896 // Properly set the subcommand to get the correct away message
897 unsigned status = _cUser->status();
898 if (status & Licq::User::DoNotDisturbStatus)
899 m_nSubCommand = ICQ_CMDxTCP_READxDNDxMSG;
900 else if (status & Licq::User::OccupiedStatus)
901 m_nSubCommand = ICQ_CMDxTCP_READxOCCUPIEDxMSG;
902 else if (status & Licq::User::NotAvailableStatus)
903 m_nSubCommand = ICQ_CMDxTCP_READxNAxMSG;
904 else if (status & Licq::User::AwayStatus)
905 m_nSubCommand = ICQ_CMDxTCP_READxAWAYxMSG;
906 else if (status & Licq::User::FreeForChatStatus)
907 m_nSubCommand = ICQ_CMDxTCP_READxFFCxMSG;
908 else
909 m_nSubCommand = ICQ_CMDxTCP_READxAWAYxMSG;
910
911 if (m_nVersion == 6)
912 m_nSize += 8;
913 InitBuffer();
914 if (m_nVersion == 6)
915 {
916 buffer->PackUnsignedLong(0xFFFFFFFF);
917 buffer->PackUnsignedLong(0xFFFFFFFF);
918 }
919 PostBuffer();
920 }
921
922 //-----ChatRequest--------------------------------------------------------------
CPT_ChatRequest(const string & message,const string & chatUsers,unsigned short nPort,unsigned short nLevel,User * pUser,bool bICBM)923 CPT_ChatRequest::CPT_ChatRequest(const string& message, const string& chatUsers,
924 unsigned short nPort, unsigned short nLevel, User* pUser, bool bICBM)
925 : CPacketTcp(ICQ_CMDxTCP_START, bICBM ? ICQ_CMDxSUB_ICBM : ICQ_CMDxSUB_CHAT,
926 DcSocket::ChannelNormal,
927 bICBM ? "" : message, true, nLevel, pUser)
928 {
929 m_nSize += 2 + chatUsers.size() + 1 + 8;
930 if (bICBM)
931 m_nSize += 47 + message.size() + 21;
932
933 InitBuffer();
934
935 if (bICBM)
936 {
937 buffer->PackUnsignedShort(0x3A);
938 buffer->PackUnsignedLongBE(0xBFF720B2);
939 buffer->PackUnsignedLongBE(0x378ED411);
940 buffer->PackUnsignedLongBE(0xBD280004);
941 buffer->PackUnsignedLongBE(0xAC96D905);
942 buffer->PackUnsignedShort(0);
943
944 buffer->PackUnsignedLong(21);
945 buffer->Pack("Send / Start ICQ Chat", 21);
946
947 buffer->PackUnsignedLongBE(0x00000100);
948 buffer->PackUnsignedLongBE(0x00010000);
949 buffer->PackUnsignedLongBE(0);
950 buffer->PackUnsignedShortBE(0);
951 buffer->PackChar(0);
952
953 buffer->PackUnsignedLong(message.size() + chatUsers.size() + 15);
954
955 buffer->PackUnsignedLong(message.size());
956
957 if (!message.empty())
958 buffer->pack(message);
959
960 buffer->packString(chatUsers);
961
962 buffer->PackUnsignedShortBE(nPort);
963 buffer->PackUnsignedShort(0);
964 buffer->PackUnsignedShort(nPort);
965 buffer->PackUnsignedShort(0);
966 }
967 else
968 {
969 buffer->packString(chatUsers);
970 buffer->packUInt16BE(nPort);
971 buffer->packUInt16BE(0);
972 buffer->PackUnsignedLong(nPort);
973 }
974
975 PostBuffer();
976 }
977
978
979 //-----FileTransfer--------------------------------------------------------------
CPT_FileTransfer(const list<string> & lFileList,const string & filename,const string & description,unsigned short nLevel,User * _cUser)980 CPT_FileTransfer::CPT_FileTransfer(const list<string>& lFileList, const string& filename,
981 const string& description, unsigned short nLevel, User* _cUser)
982 : CPacketTcp(ICQ_CMDxTCP_START, ICQ_CMDxSUB_FILE, DcSocket::ChannelNormal,
983 description, true, nLevel, _cUser),
984 m_lFileList(lFileList.begin(), lFileList.end())
985 {
986 m_bValid = false;
987 m_nFileSize = 0;
988
989 list<string>::iterator it;
990 for (it = m_lFileList.begin(); it != m_lFileList.end(); ++it)
991 {
992 // Check file exists and get size
993 struct stat buf;
994 if (!(it->empty() || stat(it->c_str(), &buf) < 0))
995 {
996 m_nFileSize += buf.st_size;
997 m_bValid = true;
998 }
999 }
1000
1001 // Remove path from filename (if it exists)
1002 myFilename = filename;
1003 size_t posSlash = myFilename.rfind('/');
1004 if (posSlash != string::npos)
1005 myFilename.erase(0, posSlash+1);
1006
1007 if (!m_bValid) return;
1008
1009 m_nSize += 15 + myFilename.size();
1010 InitBuffer();
1011
1012 buffer->PackUnsignedLong(0);
1013 buffer->packString(myFilename);
1014 buffer->PackUnsignedLong(m_nFileSize);
1015 buffer->PackUnsignedLong(0);
1016
1017 PostBuffer();
1018 }
1019
1020
1021 //-----Key------------------------------------------------------------------
CPT_OpenSecureChannel(User * _cUser)1022 CPT_OpenSecureChannel::CPT_OpenSecureChannel(User* _cUser)
1023 : CPacketTcp(ICQ_CMDxTCP_START, ICQ_CMDxSUB_SECURExOPEN,
1024 DcSocket::ChannelNormal,
1025 "", true, ICQ_TCPxMSG_NORMAL, _cUser)
1026 {
1027 InitBuffer();
1028 PostBuffer();
1029 }
1030
1031
CPT_CloseSecureChannel(User * _cUser)1032 CPT_CloseSecureChannel::CPT_CloseSecureChannel(User* _cUser)
1033 : CPacketTcp(ICQ_CMDxTCP_START, ICQ_CMDxSUB_SECURExCLOSE,
1034 DcSocket::ChannelNormal,
1035 "", true, ICQ_TCPxMSG_NORMAL, _cUser)
1036 {
1037 InitBuffer();
1038 PostBuffer();
1039 }
1040
1041
1042 //+++++Ack++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1043
CPT_Ack(unsigned short _nSubCommand,unsigned short _nSequence,bool _bAccept,bool l,User * pUser)1044 CPT_Ack::CPT_Ack(unsigned short _nSubCommand, unsigned short _nSequence,
1045 bool _bAccept, bool l, User* pUser)
1046 : CPacketTcp(ICQ_CMDxTCP_ACK, _nSubCommand, DcSocket::ChannelNormal,
1047 "", _bAccept, l ? ICQ_TCPxMSG_URGENT : ICQ_TCPxMSG_NORMAL, pUser)
1048 {
1049 m_nSequence = _nSequence;
1050 myMessage = gTranslator.fromUtf8(pUser->makeAutoResponse());
1051 }
1052
~CPT_Ack()1053 CPT_Ack::~CPT_Ack()
1054 {
1055 // Empty
1056 }
1057
1058 //-----AckGeneral---------------------------------------------------------------
CPT_AckGeneral(unsigned short nCmd,unsigned short nSequence,bool bAccept,bool nLevel,User * pUser)1059 CPT_AckGeneral::CPT_AckGeneral(unsigned short nCmd, unsigned short nSequence,
1060 bool bAccept, bool nLevel, User* pUser)
1061 : CPT_Ack(nCmd, nSequence, bAccept, nLevel, pUser)
1062 {
1063 if (m_nVersion >= 6)
1064 m_nSize += 8;
1065 InitBuffer();
1066 if (m_nVersion == 6)
1067 {
1068 buffer->PackUnsignedLong(0x00000000);
1069 buffer->PackUnsignedLong(0x00000000);
1070 }
1071 else if (m_nVersion >= 7)
1072 {
1073 buffer->PackUnsignedLong(0x00000000);
1074 buffer->PackUnsignedLong(0x00FFFFFF);
1075 }
1076
1077 PostBuffer();
1078 }
1079
1080
1081 //-----AckKey---------------------------------------------------------------
CPT_AckOpenSecureChannel(unsigned short nSequence,bool ok,User * pUser)1082 CPT_AckOpenSecureChannel::CPT_AckOpenSecureChannel(unsigned short nSequence,
1083 bool ok, User* pUser)
1084 : CPT_Ack(ICQ_CMDxSUB_SECURExOPEN, nSequence, true, true, pUser)
1085 {
1086 myMessage = (ok ? "1" : "");
1087 InitBuffer();
1088 PostBuffer();
1089 }
1090
1091
CPT_AckOldSecureChannel(unsigned short nSequence,User * pUser)1092 CPT_AckOldSecureChannel::CPT_AckOldSecureChannel(unsigned short nSequence,
1093 User* pUser)
1094 : CPT_Ack(ICQ_CMDxSUB_SECURExOPEN, nSequence, true, true, pUser)
1095 {
1096 myMessage.clear();
1097 if (m_nVersion == 6)
1098 m_nSize += 8;
1099
1100 InitBuffer();
1101 if (m_nVersion == 6)
1102 {
1103 buffer->PackUnsignedLong(0x00000000);
1104 buffer->PackUnsignedLong(0x00000000);
1105 }
1106 PostBuffer();
1107 }
1108
1109
CPT_AckCloseSecureChannel(unsigned short nSequence,User * pUser)1110 CPT_AckCloseSecureChannel::CPT_AckCloseSecureChannel(unsigned short nSequence,
1111 User* pUser)
1112 : CPT_Ack(ICQ_CMDxSUB_SECURExCLOSE, nSequence, true, true, pUser)
1113 {
1114 myMessage.clear();
1115 InitBuffer();
1116 PostBuffer();
1117 }
1118
1119
1120
1121 #if 0
1122 //-----AckMessage---------------------------------------------------------------
1123 CPT_AckMessage::CPT_AckMessage(unsigned short _nSequence, bool _bAccept,
1124 bool nLevel, User* _cUser)
1125 : CPT_Ack(ICQ_CMDxSUB_MSG, _nSequence, _bAccept, nLevel, _cUser)
1126 {
1127 InitBuffer();
1128 PostBuffer();
1129 }
1130
1131
1132
1133 //-----AckReadAwayMessage-------------------------------------------------------
1134 CPT_AckReadAwayMessage::CPT_AckReadAwayMessage(unsigned short _nSubCommand,
1135 unsigned short _nSequence, bool _bAccept, User* _cUser)
1136 : CPT_Ack(_nSubCommand, _nSequence, _bAccept, false, _cUser)
1137 {
1138 InitBuffer();
1139 PostBuffer();
1140 }
1141
1142
1143 //-----AckUrl-------------------------------------------------------------------
1144 CPT_AckUrl::CPT_AckUrl(unsigned short _nSequence, bool _bAccept, bool nLevel,
1145 User* _cUser)
1146 : CPT_Ack(ICQ_CMDxSUB_URL, _nSequence, _bAccept, nLevel, _cUser)
1147 {
1148 InitBuffer();
1149 PostBuffer();
1150 }
1151
1152
1153 //-----AckContactList--------------------------------------------------------
1154 CPT_AckContactList::CPT_AckContactList(unsigned short _nSequence, bool _bAccept,
1155 bool nLevel, User* _cUser)
1156 : CPT_Ack(ICQ_CMDxSUB_CONTACTxLIST, _nSequence, _bAccept, nLevel, _cUser)
1157 {
1158 InitBuffer();
1159 PostBuffer();
1160 }
1161 #endif
1162
1163 //-----AckChatRefuse------------------------------------------------------------
CPT_AckChatRefuse(const string & reason,unsigned short _nSequence,User * _cUser)1164 CPT_AckChatRefuse::CPT_AckChatRefuse(const string& reason,
1165 unsigned short _nSequence, User *_cUser)
1166 : CPT_Ack(ICQ_CMDxSUB_CHAT, _nSequence, false, false, _cUser)
1167 {
1168 myMessage = reason;
1169 char temp_1[11] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1170
1171 m_nSize += 11;
1172 InitBuffer();
1173 buffer->Pack(temp_1, 11);
1174 PostBuffer();
1175 }
1176
1177
1178 //-----AckChatAccept------------------------------------------------------------
CPT_AckChatAccept(unsigned short _nPort,const string & clients,unsigned short _nSequence,User * _cUser,bool bICBM)1179 CPT_AckChatAccept::CPT_AckChatAccept(unsigned short _nPort, const string& clients,
1180 unsigned short _nSequence, User* _cUser, bool bICBM)
1181 : CPT_Ack(bICBM ? ICQ_CMDxSUB_ICBM : ICQ_CMDxSUB_CHAT, _nSequence, true, true, _cUser)
1182 {
1183 m_nPort = _nPort;
1184 m_nStatus = ICQ_TCPxACK_ONLINE;
1185
1186 m_nSize += 11 + clients.size();
1187 if (bICBM)
1188 m_nSize += 68;
1189
1190 InitBuffer();
1191
1192 if (bICBM)
1193 {
1194 buffer->PackUnsignedShort(0x3A);
1195 buffer->PackUnsignedLongBE(0xBFF720B2);
1196 buffer->PackUnsignedLongBE(0x378ED411);
1197 buffer->PackUnsignedLongBE(0xBD280004);
1198 buffer->PackUnsignedLongBE(0xAC96D905);
1199 buffer->PackUnsignedShort(0);
1200
1201 buffer->PackUnsignedLong(21);
1202 buffer->Pack("Send / Start ICQ Chat", 21);
1203
1204 buffer->PackUnsignedLongBE(0x00000100);
1205 buffer->PackUnsignedLongBE(0x00010000);
1206 buffer->PackUnsignedLongBE(0);
1207 buffer->PackUnsignedShortBE(0);
1208 buffer->PackChar(0);
1209
1210 buffer->PackUnsignedLong(15 + clients.size());
1211
1212 buffer->PackUnsignedLong(0);
1213
1214 buffer->packString(clients);
1215
1216 buffer->PackUnsignedShortBE(m_nPort);
1217 buffer->PackUnsignedShort(0);
1218 buffer->PackUnsignedShort(m_nPort);
1219 buffer->PackUnsignedShort(0);
1220 }
1221 else
1222 {
1223 buffer->PackString("");
1224 buffer->packUInt16BE(m_nPort);
1225 buffer->packUInt16BE(0);
1226 buffer->PackUnsignedLong(m_nPort);
1227 }
1228
1229 PostBuffer();
1230 }
1231
1232
1233 //-----AckFileRefuse------------------------------------------------------------
CPT_AckFileRefuse(const string & reason,unsigned short _nSequence,User * _cUser)1234 CPT_AckFileRefuse::CPT_AckFileRefuse(const string& reason,
1235 unsigned short _nSequence, User* _cUser)
1236 : CPT_Ack(ICQ_CMDxSUB_FILE, _nSequence, false, false, _cUser)
1237 {
1238 myMessage = reason;
1239
1240 m_nSize += 15;
1241 InitBuffer();
1242
1243 buffer->PackUnsignedLong(0);
1244 buffer->PackString("");
1245 buffer->PackUnsignedLong(0);
1246 buffer->PackUnsignedLong(0);
1247
1248 PostBuffer();
1249 }
1250
1251
1252 //-----AckFileAccept------------------------------------------------------------
CPT_AckFileAccept(unsigned short _nPort,unsigned short _nSequence,User * _cUser)1253 CPT_AckFileAccept::CPT_AckFileAccept(unsigned short _nPort,
1254 unsigned short _nSequence, User* _cUser)
1255 : CPT_Ack(ICQ_CMDxSUB_FILE, _nSequence, true, true, _cUser)
1256 {
1257 m_nFileSize = 0;
1258 m_nPort = _nPort;
1259 m_nStatus = ICQ_TCPxACK_ONLINE;
1260
1261 m_nSize += 15;
1262 InitBuffer();
1263
1264 buffer->packUInt16BE(m_nPort);
1265 buffer->packUInt16BE(0);
1266 buffer->PackString("");
1267 buffer->PackUnsignedLong(m_nFileSize);
1268 buffer->PackUnsignedLong(m_nPort);
1269
1270 PostBuffer();
1271 }
1272
1273
1274 //+++++Cancel+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CPT_Cancel(unsigned short _nSubCommand,unsigned short _nSequence,User * _cUser)1275 CPT_Cancel::CPT_Cancel(unsigned short _nSubCommand, unsigned short _nSequence,
1276 User* _cUser)
1277 : CPacketTcp(ICQ_CMDxTCP_CANCEL, _nSubCommand, DcSocket::ChannelNormal, "", true, 0, _cUser)
1278 {
1279 m_nSequence = _nSequence;
1280 }
1281
1282
1283
1284 //-----CancelChat---------------------------------------------------------------
CPT_CancelChat(unsigned short _nSequence,User * _cUser)1285 CPT_CancelChat::CPT_CancelChat(unsigned short _nSequence, User* _cUser)
1286 : CPT_Cancel(ICQ_CMDxSUB_CHAT, _nSequence, _cUser)
1287 {
1288 char temp_1[11] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1289
1290 m_nSize += 11;
1291 InitBuffer();
1292 buffer->Pack(temp_1, 11);
1293 PostBuffer();
1294 }
1295
1296
1297 //-----CancelFile---------------------------------------------------------------
CPT_CancelFile(unsigned short _nSequence,User * _cUser)1298 CPT_CancelFile::CPT_CancelFile(unsigned short _nSequence, User* _cUser)
1299 : CPT_Cancel(ICQ_CMDxSUB_FILE, _nSequence, _cUser)
1300 {
1301 m_nSize += 15;
1302 InitBuffer();
1303
1304 buffer->PackUnsignedLong(0);
1305 buffer->PackString("");
1306 buffer->PackUnsignedLong(0);
1307 buffer->PackUnsignedLong(0);
1308
1309 PostBuffer();
1310 }
1311
1312 //-----Send error reply------------------------------------------------------
CPT_PluginError(User * _cUser,unsigned short nSequence,int channel)1313 CPT_PluginError::CPT_PluginError(User* _cUser, unsigned short nSequence,
1314 int channel)
1315 : CPacketTcp(ICQ_CMDxTCP_ACK, 0, channel, "\x03", true, 0, _cUser)
1316 {
1317 m_nSequence = nSequence;
1318
1319 InitBuffer();
1320 PostBuffer();
1321 }
1322
1323 //-----Send info plugin request------------------------------------------------
CPT_InfoPluginReq(User * _cUser,const uint8_t * GUID,unsigned long nTime)1324 CPT_InfoPluginReq::CPT_InfoPluginReq(User* _cUser, const uint8_t* GUID,
1325 unsigned long nTime)
1326 : CPacketTcp(ICQ_CMDxTCP_START, ICQ_CMDxSUB_MSG, DcSocket::ChannelInfo, "", true, 0, _cUser)
1327 {
1328 m_nSize += GUID_LENGTH + 4;
1329 memcpy(m_ReqGUID, GUID, GUID_LENGTH);
1330
1331 InitBuffer();
1332
1333 buffer->Pack(GUID, GUID_LENGTH);
1334
1335 buffer->PackUnsignedLong(nTime);
1336
1337 PostBuffer();
1338 }
1339
1340 //----Reply to phone book request-----------------------------------------------
CPT_InfoPhoneBookResp(User * _cUser,unsigned short nSequence)1341 CPT_InfoPhoneBookResp::CPT_InfoPhoneBookResp(User* _cUser,
1342 unsigned short nSequence)
1343 : CPacketTcp(ICQ_CMDxTCP_ACK, 0, DcSocket::ChannelInfo, "\x01", true, ICQ_TCPxMSG_URGENT2, _cUser)
1344 {
1345 OwnerReadGuard o(gIcqProtocol.ownerId());
1346 const Licq::IcqPhoneBookVector& book = o->getPhoneBook();
1347
1348 unsigned long nLen = 4 + 4;
1349 BOOST_FOREACH(const struct Licq::PhoneBookEntry& entry, book)
1350 {
1351 nLen += 4 + entry.description.size() + 4 + entry.areaCode.size()
1352 + 4 + entry.phoneNumber.size() + 4 + entry.extension.size()
1353 + 4 + entry.country.size() + 4 + 4 + 4
1354 + 4 + entry.gateway.size() + 4 + 4 + 4 + 4;
1355 }
1356
1357 m_nSize += 2 + 2 + 4 + 4 + nLen;
1358 m_nSequence = nSequence;
1359 InitBuffer();
1360
1361 buffer->PackUnsignedShort(0); //Unknown
1362 buffer->PackUnsignedShort(1); //Unknown
1363 buffer->PackUnsignedLong(o->ClientInfoTimestamp());
1364 buffer->PackUnsignedLong(nLen); //Bytes remaining in packet
1365
1366 buffer->PackUnsignedLong(ICQ_PLUGIN_RESP_PHONExBOOK); //Response ID
1367
1368 buffer->PackUnsignedLong(book.size());
1369
1370 BOOST_FOREACH(const struct Licq::PhoneBookEntry& entry, book)
1371 {
1372 buffer->packString32LE(entry.description);
1373 buffer->packString32LE(entry.areaCode);
1374 buffer->packString32LE(entry.phoneNumber);
1375 buffer->packString32LE(entry.extension);
1376 buffer->packString32LE(entry.country);
1377 buffer->packUInt32LE(entry.nActive);
1378 }
1379
1380 BOOST_FOREACH(const struct Licq::PhoneBookEntry& entry, book)
1381 {
1382 buffer->packUInt32LE(4 + 4 + entry.gateway.size() + 4 + 4 + 4 + 4);
1383 buffer->packUInt32LE(entry.nType);
1384 buffer->packString32LE(entry.gateway);
1385 buffer->packUInt32LE(entry.nGatewayType);
1386 buffer->packUInt32LE(entry.nSmsAvailable);
1387 buffer->packUInt32LE(entry.nRemoveLeading0s);
1388 buffer->packUInt32LE(entry.nPublish);
1389 }
1390
1391 PostBuffer();
1392 }
1393
1394 //----Reply to picture request--------------------------------------------------
CPT_InfoPictureResp(User * _cUser,unsigned short nSequence)1395 CPT_InfoPictureResp::CPT_InfoPictureResp(User* _cUser, unsigned short nSequence)
1396 : CPacketTcp(ICQ_CMDxTCP_ACK, 0, DcSocket::ChannelInfo, "\x01", true, ICQ_TCPxMSG_URGENT2, _cUser)
1397 {
1398 OwnerReadGuard o(gIcqProtocol.ownerId());
1399 string filename = o->pictureFileName();
1400 unsigned long nLen = 0, nFileLen = 0;
1401 int fd = -1;
1402 if (o->GetPicturePresent())
1403 {
1404 fd = open(filename.c_str(), O_RDONLY);
1405 if (fd == -1)
1406 {
1407 gLog.error(tr("Unable to open picture file (%s): %s."),
1408 filename.c_str(), strerror(errno));
1409 }
1410 else
1411 {
1412 struct stat fi;
1413 if (fstat(fd, &fi) == -1)
1414 {
1415 gLog.error(tr("Unable to stat picture file (%s):%s."),
1416 filename.c_str(), strerror(errno));
1417 }
1418 else
1419 {
1420 nFileLen = fi.st_size;
1421 nLen = 4 + 4 + 1 + 4 + nFileLen;
1422 }
1423 }
1424 }
1425
1426 m_nSize += 2 + 2 + 4 + 4 + nLen;
1427 m_nSequence = nSequence;
1428 InitBuffer();
1429
1430 buffer->PackUnsignedShort(0); //Unknown
1431 buffer->PackUnsignedShort(1); //Unknown
1432 buffer->PackUnsignedLong(o->ClientInfoTimestamp());
1433 buffer->PackUnsignedLong(nLen); //Bytes remaining in packet
1434
1435 if (nLen != 0)
1436 {
1437 buffer->PackUnsignedLong(ICQ_PLUGIN_RESP_PICTURE); //Response ID
1438
1439 buffer->PackUnsignedLong(1); //filename length
1440 buffer->PackChar('p'); //windows icq needs a filename
1441
1442 buffer->PackUnsignedLong(nFileLen);
1443
1444 char buf[8192];
1445 unsigned long nRead = 0;
1446 while (nRead < nFileLen)
1447 {
1448 unsigned long nToRead;
1449 if (sizeof(buf) < nFileLen - nRead)
1450 nToRead = sizeof(buf);
1451 else
1452 nToRead = nFileLen - nRead;
1453
1454 ssize_t nBytesRead = read(fd, buf, nToRead);
1455 if (nBytesRead == -1)
1456 {
1457 gLog.error(tr("Failed to read file (%s): %s."),
1458 filename.c_str(), strerror(errno));
1459 break;
1460 }
1461 if (nBytesRead == 0)
1462 {
1463 gLog.error(tr("Premature end of file (%s): %s."),
1464 filename.c_str(), strerror(errno));
1465 break;
1466 }
1467
1468 nRead += nBytesRead;
1469 for (ssize_t i = 0; i < nBytesRead; i++)
1470 buffer->PackChar(buf[i]);
1471 }
1472
1473 if (nRead < nFileLen)
1474 {
1475 //failed to read as much as predicted, fill with 0s
1476 for (; nRead < nFileLen; nRead++)
1477 buffer->PackChar(0);
1478 }
1479 }
1480
1481 if (fd != -1)
1482 close(fd);
1483 }
1484
1485 //----Reply to plugin list request----------------------------------------------
CPT_InfoPluginListResp(User * _cUser,unsigned short nSequence)1486 CPT_InfoPluginListResp::CPT_InfoPluginListResp(User* _cUser, unsigned short nSequence)
1487 : CPacketTcp(ICQ_CMDxTCP_ACK, 0, DcSocket::ChannelInfo, "\x01", true, ICQ_TCPxMSG_URGENT2, _cUser)
1488 {
1489 unsigned long num_plugins = sizeof(IcqProtocol::info_plugins)/sizeof(struct PluginList);
1490
1491 unsigned long nLen;
1492 if (num_plugins == 0)
1493 nLen = 0;
1494 else
1495 {
1496 nLen = 4 + 4;
1497 for (unsigned long i = 0; i < num_plugins; i ++)
1498 {
1499 nLen += GUID_LENGTH + 2 + 2 + 4 + strlen(IcqProtocol::info_plugins[i].name)
1500 + 4 + strlen(IcqProtocol::info_plugins[i].description) + 4;
1501 }
1502 }
1503
1504 m_nSize += 2 + 2 + 4 + 4 + nLen;
1505 m_nSequence = nSequence;
1506 InitBuffer();
1507
1508 buffer->PackUnsignedShort(0); //Unknown
1509 buffer->PackUnsignedShort(1); //Unknown
1510 {
1511 OwnerReadGuard o(gIcqProtocol.ownerId());
1512 buffer->PackUnsignedLong(o->ClientInfoTimestamp());
1513 }
1514 buffer->PackUnsignedLong(nLen); //Bytes remaining in packet
1515 if (nLen != 0)
1516 {
1517 buffer->PackUnsignedLong(ICQ_PLUGIN_RESP_INFOxLIST); //Response ID
1518 buffer->PackUnsignedLong(num_plugins);
1519 for (unsigned long i = 0; i < num_plugins; i++)
1520 {
1521 buffer->packRaw(IcqProtocol::info_plugins[i].guid, GUID_LENGTH);
1522
1523 buffer->PackUnsignedShort(0); //Unknown
1524 buffer->PackUnsignedShort(1); //Unknown
1525
1526 buffer->packString32LE(IcqProtocol::info_plugins[i].name,
1527 strlen(IcqProtocol::info_plugins[i].name));
1528
1529 buffer->packString32LE(IcqProtocol::info_plugins[i].description,
1530 strlen(IcqProtocol::info_plugins[i].description));
1531
1532 buffer->PackUnsignedLong(0); //Unknown
1533 }
1534 }
1535 PostBuffer();
1536 }
1537
1538 //-----Send status plugin request----------------------------------------------
CPT_StatusPluginReq(User * _cUser,const uint8_t * GUID,unsigned long nTime)1539 CPT_StatusPluginReq::CPT_StatusPluginReq(User* _cUser, const uint8_t* GUID,
1540 unsigned long nTime)
1541 : CPacketTcp(ICQ_CMDxTCP_START, ICQ_CMDxSUB_MSG, DcSocket::ChannelStatus, "", true, 0, _cUser)
1542 {
1543 m_nSize += GUID_LENGTH + 4;
1544 memcpy(m_ReqGUID, GUID, GUID_LENGTH);
1545
1546 InitBuffer();
1547
1548 buffer->Pack(GUID, GUID_LENGTH);
1549
1550 buffer->PackUnsignedLong(nTime);
1551
1552 PostBuffer();
1553 }
1554
1555 //----Reply to plugin list request----------------------------------------------
CPT_StatusPluginListResp(User * _cUser,unsigned short nSequence)1556 CPT_StatusPluginListResp::CPT_StatusPluginListResp(User* _cUser, unsigned short nSequence)
1557 : CPacketTcp(ICQ_CMDxTCP_ACK, 0, DcSocket::ChannelStatus, "\x01", true, 0, _cUser)
1558 {
1559 unsigned long num_plugins = sizeof(IcqProtocol::status_plugins)/sizeof(struct PluginList);
1560
1561 unsigned long nLen;
1562 if (num_plugins == 0)
1563 nLen = 0;
1564 else
1565 {
1566 nLen = 4 + 4;
1567 for (unsigned long i = 0; i < num_plugins; i ++)
1568 {
1569 nLen += GUID_LENGTH + 2 + 2 + 4 + strlen(IcqProtocol::status_plugins[i].name)
1570 + 4 + strlen(IcqProtocol::status_plugins[i].description) + 4;
1571 }
1572 }
1573
1574 m_nSize += 13 + 4 + 4 + nLen;
1575 m_nSequence = nSequence;
1576 InitBuffer();
1577
1578 buffer->PackUnsignedShort(0); //Unknown
1579 buffer->PackUnsignedShort(1); //Unknown
1580 buffer->PackUnsignedLong(0); //Unknown
1581 buffer->PackUnsignedLong(0); //Unknown
1582 buffer->PackChar(1); //Unknown
1583 {
1584 OwnerReadGuard o(gIcqProtocol.ownerId());
1585 buffer->PackUnsignedLong(o->ClientStatusTimestamp());
1586 }
1587 buffer->PackUnsignedLong(nLen); //Bytes remaining in packet
1588 if (nLen != 0)
1589 {
1590 buffer->PackUnsignedLong(ICQ_PLUGIN_RESP_STATUSxLIST); //Response ID
1591 buffer->PackUnsignedLong(num_plugins);
1592 for (unsigned long i = 0; i < num_plugins; i++)
1593 {
1594 buffer->packRaw(IcqProtocol::status_plugins[i].guid, GUID_LENGTH);
1595
1596 buffer->PackUnsignedShort(0); //Unknown
1597 buffer->PackUnsignedShort(1); //Unknown
1598
1599 buffer->packString32LE(IcqProtocol::status_plugins[i].name,
1600 strlen(IcqProtocol::status_plugins[i].name));
1601
1602 buffer->packString32LE(IcqProtocol::status_plugins[i].description,
1603 strlen(IcqProtocol::status_plugins[i].description));
1604
1605 buffer->PackUnsignedLong(0); //Unknown
1606 }
1607 }
1608 PostBuffer();
1609 }
1610
1611 //----Reply to status request--------------------------------------------------
CPT_StatusPluginResp(User * _cUser,unsigned short nSequence,unsigned long nStatus)1612 CPT_StatusPluginResp::CPT_StatusPluginResp(User* _cUser,
1613 unsigned short nSequence,
1614 unsigned long nStatus)
1615 : CPacketTcp(ICQ_CMDxTCP_ACK, 0, DcSocket::ChannelStatus, "\x02", true, 0, _cUser)
1616 {
1617 m_nSize += 2 + 2 + 4 + 4 + 1;
1618 m_nSequence = nSequence;
1619 InitBuffer();
1620
1621 buffer->PackUnsignedShort(0); //Unknown
1622 buffer->PackUnsignedShort(1); //Unknown
1623 buffer->PackUnsignedLong(nStatus);
1624 {
1625 OwnerReadGuard o(gIcqProtocol.ownerId());
1626 buffer->PackUnsignedLong(o->ClientStatusTimestamp());
1627 }
1628 buffer->PackChar(1); //Unknown
1629
1630 PostBuffer();
1631 }
1632