1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 1998-2013 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 "chat.h"
21
22 #include <cctype>
23 #include <cstdio>
24 #include <cstring>
25 #include <unistd.h>
26
27 #include <licq/logging/log.h>
28 #include <licq/contactlist/owner.h>
29 #include <licq/contactlist/usermanager.h>
30 #include <licq/daemon.h>
31 #include <licq/translator.h>
32
33 #include "gettext.h"
34 #include "icq.h"
35 #include "packet-tcp.h"
36 #include "socket.h"
37 #include "user.h"
38
39 using namespace LicqIcq;
40 using Licq::gDaemon;
41 using Licq::gLog;
42 using Licq::gTranslator;
43 using Licq::IcqChatEvent;
44 using std::string;
45
46 using Licq::CHAT_BACKSPACE;
47 using Licq::CHAT_BEEP;
48 using Licq::CHAT_CHARACTER;
49 using Licq::CHAT_COLORxBG;
50 using Licq::CHAT_COLORxFG;
51 using Licq::CHAT_CONNECTION;
52 using Licq::CHAT_DISCONNECTION;
53 using Licq::CHAT_DISCONNECTIONxKICKED;
54 using Licq::CHAT_ERRORxBIND;
55 using Licq::CHAT_ERRORxCONNECT;
56 using Licq::CHAT_ERRORxRESOURCES;
57 using Licq::CHAT_FOCUSxIN;
58 using Licq::CHAT_FOCUSxOUT;
59 using Licq::CHAT_FONTxFACE;
60 using Licq::CHAT_FONTxFAMILY;
61 using Licq::CHAT_FONTxSIZE;
62 using Licq::CHAT_KICK;
63 using Licq::CHAT_KICKxFAIL;
64 using Licq::CHAT_KICKxNO;
65 using Licq::CHAT_KICKxPASS;
66 using Licq::CHAT_KICKxYES;
67 using Licq::CHAT_KICKxYOU;
68 using Licq::CHAT_LAUGH;
69 using Licq::CHAT_NEWLINE;
70 using Licq::CHAT_SLEEPxOFF;
71 using Licq::CHAT_SLEEPxON;
72 using Licq::FONT_BOLD;
73 using Licq::FONT_ITALIC;
74 using Licq::FONT_PLAIN;
75 using Licq::FONT_STRIKEOUT;
76 using Licq::FONT_UNDERLINE;
77
78 #define MAX_CONNECTS 256
79 #define DEBUG_THREADS(x)
80
81
82 const unsigned short CHAT_STATE_DISCONNECTED = 0;
83 const unsigned short CHAT_STATE_HANDSHAKE = 1;
84 const unsigned short CHAT_STATE_WAITxFORxCOLOR = 2;
85 const unsigned short CHAT_STATE_WAITxFORxCOLORxFONT = 3;
86 const unsigned short CHAT_STATE_WAITxFORxFONT = 4;
87 const unsigned short CHAT_STATE_CONNECTED = 5;
88
89
90 //---Chat-----------------------------------------------------------------------
CPacketChat()91 CPacketChat::CPacketChat()
92 : buffer(NULL)
93 {
94 // Empty
95 }
96
~CPacketChat()97 CPacketChat::~CPacketChat()
98 {
99 delete buffer;
100 }
101
InitBuffer()102 void CPacketChat::InitBuffer()
103 {
104 buffer = new CBuffer(m_nSize);
105 }
106
107 //-----ChatColor----------------------------------------------------------------
CPChat_Color(const string & localName,unsigned short _nLocalPort,int nColorForeRed,int nColorForeGreen,int nColorForeBlue,int nColorBackRed,int nColorBackBlue,int nColorBackGreen)108 CPChat_Color::CPChat_Color(const string& localName, unsigned short _nLocalPort,
109 int nColorForeRed, int nColorForeGreen, int nColorForeBlue, int nColorBackRed,
110 int nColorBackBlue, int nColorBackGreen)
111 {
112 m_nPort = _nLocalPort;
113 Licq::UserId userId(gIcqProtocol.ownerId());
114 myUin = atol(userId.accountId().c_str());
115 m_nColorForeRed = nColorForeRed;
116 m_nColorForeGreen = nColorForeGreen;
117 m_nColorForeBlue = nColorForeBlue;
118 m_nColorBackRed = nColorBackRed;
119 m_nColorBackGreen = nColorBackGreen;
120 m_nColorBackBlue = nColorBackBlue;
121
122 m_nSize = 10 + localName.size() + 16;
123 InitBuffer();
124
125 buffer->PackUnsignedLong(0x65);
126 buffer->PackUnsignedLong(-ICQ_VERSION_TCP);
127 buffer->PackUnsignedLong(myUin);
128 buffer->PackString(localName.c_str());
129 buffer->packUInt16BE(_nLocalPort);
130 buffer->PackChar(nColorForeRed);
131 buffer->PackChar(nColorForeGreen);
132 buffer->PackChar(nColorForeBlue);
133 buffer->PackChar(0);
134 buffer->PackChar(nColorBackRed);
135 buffer->PackChar(nColorBackGreen);
136 buffer->PackChar(nColorBackBlue);
137 buffer->PackChar(0);
138 buffer->PackChar(0);
139 }
140
141
CPChat_Color(CBuffer & b)142 CPChat_Color::CPChat_Color(CBuffer &b)
143 {
144 b.unpackUInt16LE(); // Packet length
145 b.UnpackUnsignedLong();
146 b.UnpackUnsignedLong();
147 myUin = b.UnpackUnsignedLong();
148 myName = b.unpackShortStringLE();
149 m_nPort = b.UnpackUnsignedShort();
150 m_nPort = (m_nPort >> 8) + (m_nPort << 8);
151 m_nColorForeRed = (unsigned char)b.UnpackChar();
152 m_nColorForeGreen = (unsigned char)b.UnpackChar();
153 m_nColorForeBlue = (unsigned char)b.UnpackChar();
154 b.UnpackChar();
155 m_nColorBackRed = (unsigned char)b.UnpackChar();
156 m_nColorBackGreen = (unsigned char)b.UnpackChar();
157 m_nColorBackBlue = (unsigned char)b.UnpackChar();
158 b.UnpackChar();
159 }
160
~CPChat_Color()161 CPChat_Color::~CPChat_Color()
162 {
163 // Empty
164 }
165
166
167 //-----ChatColorFont----------------------------------------------------------------
ChatClient()168 ChatClient::ChatClient()
169 {
170 m_nVersion = m_nIp = m_nIntIp = m_nPort = m_nMode
171 = m_nSession = m_nHandshake = 0;
172 }
173
174
ChatClient(const User * u)175 ChatClient::ChatClient(const User* u)
176 {
177 m_nVersion = u->Version();
178 myUin = atol(u->id().accountId().c_str());
179 m_nIp = u->Ip();
180 m_nIntIp = u->IntIp();
181 m_nMode = (u->directMode() ? MODE_DIRECT : MODE_INDIRECT);
182 m_nSession = 0;
183 m_nHandshake = 0x65;
184
185 // These will still need to be set
186 m_nPort = 0;
187 m_nSession = 0;
188 }
189
190
ChatClient(CBuffer & b)191 ChatClient::ChatClient(CBuffer &b)
192 {
193 LoadFromBuffer(b);
194 }
195
ChatClient(const ChatClient & p)196 ChatClient::ChatClient(const ChatClient &p)
197 {
198 *this = p;
199 }
200
~ChatClient()201 ChatClient::~ChatClient()
202 {
203 }
204
operator =(const ChatClient & p)205 ChatClient& ChatClient::operator=(const ChatClient &p)
206 {
207 if (this != &p)
208 {
209 m_nVersion = p.m_nVersion;
210 m_nPort = p.m_nPort;
211 myUin = p.myUin;
212 m_nIp = p.m_nIp;
213 m_nIntIp = p.m_nIntIp;
214 m_nMode = p.m_nMode;
215 m_nSession = p.m_nSession;
216 m_nHandshake = p.m_nHandshake;
217 }
218 return *this;
219 }
220
LoadFromBuffer(CBuffer & b)221 bool ChatClient::LoadFromBuffer(CBuffer &b)
222 {
223 m_nVersion = b.UnpackUnsignedLong();
224 m_nPort = b.UnpackUnsignedShort();
225 b.UnpackUnsignedShort();
226 myUin = b.UnpackUnsignedLong();
227 m_nIp = b.UnpackUnsignedLong();
228 m_nIntIp = b.UnpackUnsignedLong();
229 m_nMode = b.UnpackChar();
230 b.UnpackUnsignedShort();
231 m_nSession = b.UnpackUnsignedShort();
232 m_nHandshake = b.UnpackUnsignedLong();
233
234 return true;
235 }
236
237
LoadFromHandshake_v2(CBuffer & b)238 bool ChatClient::LoadFromHandshake_v2(CBuffer &b)
239 {
240 b.Reset();
241 b.unpackUInt16LE(); // Packet length
242
243 if ((unsigned char)b.UnpackChar() != ICQ_CMDxTCP_HANDSHAKE) return false;
244
245 m_nVersion = b.UnpackUnsignedLong();
246 b.UnpackUnsignedLong();
247 myUin = b.UnpackUnsignedLong();
248 m_nIp = b.UnpackUnsignedLong();
249 m_nIntIp = b.UnpackUnsignedLong();
250 m_nMode = b.UnpackChar();
251 m_nHandshake = 0x64;
252
253 // These will still need to be set
254 m_nPort = 0;
255 m_nSession = 0;
256
257 return true;
258 }
259
260
LoadFromHandshake_v4(CBuffer & b)261 bool ChatClient::LoadFromHandshake_v4(CBuffer &b)
262 {
263 b.Reset();
264 b.unpackUInt16LE(); // Packet length
265
266 if ((unsigned char)b.UnpackChar() != ICQ_CMDxTCP_HANDSHAKE) return false;
267
268 m_nVersion = b.UnpackUnsignedLong();
269 b.UnpackUnsignedLong();
270 myUin = b.UnpackUnsignedLong();
271 m_nIp = b.UnpackUnsignedLong(); // Will probably be zero...
272 m_nIntIp = b.UnpackUnsignedLong();
273 m_nMode = b.UnpackChar();
274 m_nHandshake = 0x64;
275
276 // These will still need to be set
277 m_nPort = 0;
278 m_nSession = 0;
279
280 return true;
281 }
282
283
LoadFromHandshake_v6(CBuffer & b)284 bool ChatClient::LoadFromHandshake_v6(CBuffer &b)
285 {
286 CPacketTcp_Handshake_v6 hand(&b);
287
288 m_nVersion = hand.VersionMajor();
289 myUin = hand.SourceUin();
290 m_nIntIp = hand.LocalIp();
291 m_nIp = hand.RealIp();
292 m_nMode = hand.Mode();
293 m_nHandshake = 0x64;
294
295 // These will still need to be set
296 m_nPort = 0;
297 m_nSession = 0;
298
299 return true;
300 }
301
302
LoadFromHandshake_v7(CBuffer & b)303 bool ChatClient::LoadFromHandshake_v7(CBuffer &b)
304 {
305 CPacketTcp_Handshake_v7 hand(&b);
306
307 m_nVersion = hand.VersionMajor();
308 myUin = hand.SourceUin();
309 m_nIntIp = hand.LocalIp();
310 m_nIp = hand.RealIp();
311 m_nMode = hand.Mode();
312 m_nHandshake = 0x65;
313
314 // These will still need to be set
315 m_nPort = 0;
316 m_nSession = 0;
317
318 return true;
319 }
320
321
CPChat_ColorFont(const string & localName,unsigned short nLocalPort,unsigned short nSession,int nColorForeRed,int nColorForeGreen,int nColorForeBlue,int nColorBackRed,int nColorBackBlue,int nColorBackGreen,unsigned long nFontSize,bool bFontBold,bool bFontItalic,bool bFontUnderline,bool bFontStrikeOut,const string & fontFamily,unsigned char nFontEncoding,unsigned char nFontStyle,ChatClientPList & clientList)322 CPChat_ColorFont::CPChat_ColorFont(const string& localName, unsigned short nLocalPort,
323 unsigned short nSession,
324 int nColorForeRed, int nColorForeGreen, int nColorForeBlue, int nColorBackRed,
325 int nColorBackBlue, int nColorBackGreen,
326 unsigned long nFontSize,
327 bool bFontBold, bool bFontItalic, bool bFontUnderline, bool bFontStrikeOut,
328 const string& fontFamily, unsigned char nFontEncoding,
329 unsigned char nFontStyle, ChatClientPList &clientList)
330 {
331 m_nPort = nLocalPort;
332 Licq::UserId userId(gIcqProtocol.ownerId());
333 myUin = atol(userId.accountId().c_str());
334 m_nColorForeRed = nColorForeRed;
335 m_nColorForeGreen = nColorForeGreen;
336 m_nColorForeBlue = nColorForeBlue;
337 m_nColorBackRed = nColorBackRed;
338 m_nColorBackGreen = nColorBackGreen;
339 m_nColorBackBlue = nColorBackBlue;
340 m_nSession = nSession;
341 m_nFontSize = nFontSize;
342 m_nFontFace = FONT_PLAIN;
343 if (bFontBold) m_nFontFace |= FONT_BOLD;
344 if (bFontItalic) m_nFontFace |= FONT_ITALIC;
345 if (bFontUnderline) m_nFontFace |= FONT_UNDERLINE;
346 if (bFontStrikeOut) m_nFontFace |= FONT_STRIKEOUT;
347 m_nFontEncoding = nFontEncoding;
348 m_nFontStyle = nFontStyle;
349
350 m_nSize = 10 + localName.size() + 38 + fontFamily.size() + 4
351 + clientList.size() * (sizeof(ChatClient) + 2);
352 InitBuffer();
353
354 buffer->PackUnsignedLong(0x65);
355 buffer->PackUnsignedLong(myUin);
356 buffer->PackString(localName.c_str());
357 buffer->PackChar(nColorForeRed);
358 buffer->PackChar(nColorForeGreen);
359 buffer->PackChar(nColorForeBlue);
360 buffer->PackChar(0);
361 buffer->PackChar(nColorBackRed);
362 buffer->PackChar(nColorBackGreen);
363 buffer->PackChar(nColorBackBlue);
364 buffer->PackChar(0);
365 buffer->PackUnsignedLong(ICQ_VERSION_TCP);
366 buffer->PackUnsignedLong(m_nPort);
367 buffer->PackUnsignedLong(s_nLocalIp);
368 buffer->PackUnsignedLong(s_nRealIp);
369 buffer->PackChar(gIcqProtocol.directMode() ? MODE_DIRECT : MODE_INDIRECT);
370 buffer->PackUnsignedShort(m_nSession);
371 buffer->PackUnsignedLong(m_nFontSize);
372 buffer->PackUnsignedLong(m_nFontFace);
373 buffer->PackString(fontFamily.c_str());
374 buffer->PackChar(nFontEncoding);
375 buffer->PackChar(nFontStyle);
376 buffer->PackChar(clientList.size());
377
378 ChatClientPList::iterator iter;
379 for (iter = clientList.begin(); iter != clientList.end(); ++iter)
380 {
381 buffer->PackUnsignedLong((*iter)->m_nVersion);
382 buffer->PackUnsignedLong((*iter)->m_nPort);
383 buffer->PackUnsignedLong((*iter)->myUin);
384 buffer->PackUnsignedLong((*iter)->m_nIp);
385 buffer->PackUnsignedLong((*iter)->m_nIntIp);
386 buffer->PackChar((*iter)->m_nMode);
387 buffer->PackUnsignedShort((*iter)->m_nPort);
388 buffer->PackUnsignedShort((*iter)->m_nSession);
389 buffer->PackUnsignedLong((*iter)->m_nHandshake);
390 }
391 }
392
393
CPChat_ColorFont(CBuffer & b)394 CPChat_ColorFont::CPChat_ColorFont(CBuffer &b)
395 {
396 b.unpackUInt16LE(); // Packet length
397 b.UnpackUnsignedLong();
398 myUin = b.UnpackUnsignedLong();
399 myName = b.unpackShortStringLE();
400 m_nColorForeRed = (unsigned char)b.UnpackChar();
401 m_nColorForeGreen = (unsigned char)b.UnpackChar();
402 m_nColorForeBlue = (unsigned char)b.UnpackChar();
403 b.UnpackChar();
404 m_nColorBackRed = (unsigned char)b.UnpackChar();
405 m_nColorBackGreen = (unsigned char)b.UnpackChar();
406 m_nColorBackBlue = (unsigned char)b.UnpackChar();
407 b.UnpackChar();
408
409 b.UnpackUnsignedLong();
410 m_nPort = b.UnpackUnsignedLong();
411 b.UnpackUnsignedLong();
412 b.UnpackUnsignedLong();
413 b.UnpackChar();
414 m_nSession = b.UnpackUnsignedShort();
415 m_nFontSize = b.UnpackUnsignedLong();
416 m_nFontFace = b.UnpackUnsignedLong();
417 myFontFamily = b.unpackShortStringLE();
418 m_nFontEncoding = b.UnpackChar();
419 m_nFontStyle = b.UnpackChar();
420
421 // Read out client packets
422 unsigned short nc = b.UnpackChar();
423 for (unsigned short i = 0; i < nc; i++)
424 {
425 chatClients.push_back(ChatClient(b));
426 }
427
428 }
429
~CPChat_ColorFont()430 CPChat_ColorFont::~CPChat_ColorFont()
431 {
432 // Empty
433 }
434
435 //-----ChatFont---------------------------------------------------------------------
CPChat_Font(unsigned short nLocalPort,unsigned short nSession,unsigned long nFontSize,bool bFontBold,bool bFontItalic,bool bFontUnderline,bool bFontStrikeOut,const string & fontFamily,unsigned char nFontEncoding,unsigned char nFontStyle)436 CPChat_Font::CPChat_Font(unsigned short nLocalPort, unsigned short nSession,
437 unsigned long nFontSize,
438 bool bFontBold, bool bFontItalic, bool bFontUnderline,
439 bool bFontStrikeOut, const string& fontFamily,
440 unsigned char nFontEncoding, unsigned char nFontStyle)
441 {
442 m_nPort = nLocalPort;
443 m_nSession = nSession;
444 m_nFontSize = nFontSize;
445 m_nFontFace = FONT_PLAIN;
446 if (bFontBold) m_nFontFace |= FONT_BOLD;
447 if (bFontItalic) m_nFontFace |= FONT_ITALIC;
448 if (bFontUnderline) m_nFontFace |= FONT_UNDERLINE;
449 if (bFontStrikeOut) m_nFontFace |= FONT_STRIKEOUT;
450 m_nFontEncoding = nFontEncoding;
451 m_nFontStyle = nFontStyle;
452
453 m_nSize = 29 + fontFamily.size() + 3;
454 InitBuffer();
455
456 buffer->PackUnsignedLong(ICQ_VERSION_TCP);
457 buffer->PackUnsignedLong(m_nPort);
458 buffer->PackUnsignedLong(s_nLocalIp);
459 buffer->PackUnsignedLong(s_nRealIp);
460 buffer->PackChar(gIcqProtocol.directMode() ? MODE_DIRECT : MODE_INDIRECT);
461 buffer->PackUnsignedShort(nSession);//0x5A89);
462 buffer->PackUnsignedLong(m_nFontSize);
463 buffer->PackUnsignedLong(m_nFontFace);
464 buffer->PackString(fontFamily.c_str());
465 buffer->PackChar(nFontEncoding);
466 buffer->PackChar(nFontStyle);
467 }
468
CPChat_Font(CBuffer & b)469 CPChat_Font::CPChat_Font(CBuffer &b)
470 {
471 b.unpackUInt16LE(); // Packet length
472 b.UnpackUnsignedLong();
473 m_nPort = b.UnpackUnsignedLong();
474 b.UnpackUnsignedLong();
475 b.UnpackUnsignedLong();
476 b.UnpackChar();
477 m_nSession = b.UnpackUnsignedShort();
478 m_nFontSize = b.UnpackUnsignedLong();
479 m_nFontFace = b.UnpackUnsignedLong();
480 myFontFamily = b.unpackShortStringLE();
481 m_nFontEncoding = b.UnpackChar();
482 m_nFontStyle = b.UnpackChar();
483 }
484
~CPChat_Font()485 CPChat_Font::~CPChat_Font()
486 {
487 // Empty
488 }
489
490 /*
491 //-----CPChat_ChangeFontFamily-----------------------------------------------
492 CPChat_ChangeFontFamily::CPChat_ChangeFontFamily(const string& fontFamily)
493 {
494 m_nSize = fontFamily.size() + 6;
495 InitBuffer();
496
497 buffer->PackChar(CHAT_FONTxFAMILY);
498 buffer->PackString(fontFamily.c_str());
499 buffer->PackUnsignedShort(0x2200);
500 // 0x2200 west
501 // 0x22a2 turkey
502 // 0x22cc cyrillic
503 // 0x22a1 greek
504 // 0x22ba baltic
505 }
506
507
508 CPChat_ChangeFontFamily::CPChat_ChangeFontFamily(CBuffer &b)
509 {
510 //b.UnpackChar(); // CHAT_CHANGExFONT
511 myFontFamily = b.unpackShortStringLE();
512 b.UnpackUnsignedShort(); // Charset?
513 }
514
515
516 //-----CPChat_ChangeFontFamily-----------------------------------------------
517 CPChat_ChangeFontSize::CPChat_ChangeFontSize(unsigned short nSize)
518 {
519 m_nFontSize = nSize;
520
521 m_nSize = 3;
522 InitBuffer();
523
524 buffer->PackChar(CHAT_FONTxSIZE);
525 buffer->PackUnsignedLong(nSize);
526 }
527
528
529 CPChat_ChangeFontSize::CPChat_ChangeFontSize(CBuffer &b)
530 {
531 //b.UnpackChar();
532 m_nFontSize = b.UnpackUnsignedLong();
533 }
534
535
536
537 //-----CPChat_ChangeFontFace-----------------------------------------------
538 CPChat_ChangeFontFace::CPChat_ChangeFontFace(bool bBold, bool bItalic,
539 bool bUnderline)
540 {
541 m_nFontFace = FONT_PLAIN;
542 if (bBold) m_nFontFace |= FONT_BOLD;
543 if (bItalic) m_nFontFace |= FONT_ITALIC;
544 if (bUnderline) m_nFontFace |= FONT_UNDERLINE;
545
546 m_nSize = 5;
547 InitBuffer();
548
549 buffer->PackChar(CHAT_FONTxFACE);
550 buffer->PackUnsignedLong(m_nFontFace);
551 }
552
553
554 CPChat_ChangeFontFace::CPChat_ChangeFontFace(CBuffer &b)
555 {
556 //b.UnpackChar();
557 m_nFontFace = b.UnpackUnsignedLong();
558 }
559
560
561 CPChat_ChangeColorBg::CPChat_ChangeColorBg(int nRed, int nGreen, int nBlue)
562 {
563 m_nColorBackRed = nRed;
564 m_nColorBackGreen = nGreen;
565 m_nColorBackBlue = nBlue;
566
567 m_nSize = 5;
568 InitBuffer();
569
570 buffer->PackChar(CHAT_COLORxBG);
571 buffer->PackChar(nRed);
572 buffer->PackChar(nGreen);
573 buffer->PackChar(nBlue);
574 buffer->PackChar(0);
575 }
576
577
578 CPChat_ChangeColorBg::CPChat_ChangeColorBg(CBuffer &b)
579 {
580 //b.UnpackChar();
581 m_nColorBackRed = (unsigned char)b.UnpackChar();
582 m_nColorBackGreen = (unsigned char)b.UnpackChar();
583 m_nColorBackBlue = (unsigned char)b.UnpackChar();
584 b.UnpackChar();
585 }
586
587
588 CPChat_ChangeColorFg::CPChat_ChangeColorFg(int nRed, int nGreen, int nBlue)
589 {
590 m_nColorForeRed = nRed;
591 m_nColorForeGreen = nGreen;
592 m_nColorForeBlue = nBlue;
593
594 m_nSize = 5;
595 InitBuffer();
596
597 buffer->PackChar(CHAT_COLORxFG);
598 buffer->PackChar(nRed);
599 buffer->PackChar(nGreen);
600 buffer->PackChar(nBlue);
601 buffer->PackChar(0);
602 }
603
604
605 CPChat_ChangeColorFg::CPChat_ChangeColorFg(CBuffer &b)
606 {
607 //b.UnpackChar();
608 m_nColorForeRed = (unsigned char)b.UnpackChar();
609 m_nColorForeGreen = (unsigned char)b.UnpackChar();
610 m_nColorForeBlue = (unsigned char)b.UnpackChar();
611 b.UnpackChar();
612 }
613
614
615 CPChat_Beep::CPChat_Beep()
616 {
617 m_nSize = 1;
618 InitBuffer();
619
620 buffer->PackChar(CHAT_BEEP);
621 }
622 */
623
624
625 //=====ChatUser==============================================================
IcqChatUser()626 Licq::IcqChatUser::IcqChatUser()
627 {
628 // Empty
629 }
630
~IcqChatUser()631 Licq::IcqChatUser::~IcqChatUser()
632 {
633 // Empty
634 }
635
ChatUser()636 ChatUser::ChatUser()
637 {
638 nToKick = 0;
639 state = CHAT_STATE_DISCONNECTED;
640 colorFore[0] = colorFore[1] = colorFore[2] = 0x00;
641 colorBack[0] = colorBack[1] = colorBack[2] = 0xFF;
642 myFontFamily = "courier";
643 fontEncoding = Licq::ENCODING_DEFAULT;
644 fontStyle = Licq::STYLE_MODERN | Licq::STYLE_FIXEDxPITCH; // style of courier
645 fontSize = 12;
646 fontFace = FONT_PLAIN;
647 focus = true;
648 sleep = false;
649 m_pClient = NULL;
650
651 pthread_mutex_init(&mutex, NULL);
652 }
653
~ChatUser()654 ChatUser::~ChatUser()
655 {
656 // Empty
657 }
658
IcqChatEvent(unsigned char nCommand,Licq::IcqChatUser * u,const string & data)659 Licq::IcqChatEvent::IcqChatEvent(unsigned char nCommand, Licq::IcqChatUser* u, const string& data)
660 : myData(data)
661 {
662 m_nCommand = nCommand;
663 m_pUser = u;
664 m_bLocked = false;
665 }
666
667
~IcqChatEvent()668 Licq::IcqChatEvent::~IcqChatEvent()
669 {
670 if (m_bLocked)
671 pthread_mutex_unlock(&(dynamic_cast<ChatUser*>(m_pUser)->mutex));
672 }
673
674 //=====ChatManager===========================================================
675 ChatManagerList ChatManager::cmList;
676 pthread_mutex_t ChatManager::cmList_mutex = PTHREAD_MUTEX_INITIALIZER;
677 pthread_mutex_t ChatManager::waiting_thread_cancel_mutex
678 = PTHREAD_MUTEX_INITIALIZER;
679
~IcqChatManager()680 Licq::IcqChatManager::~IcqChatManager()
681 {
682 // Empty
683 }
684
ChatManager(const Licq::UserId & userId)685 ChatManager::ChatManager(const Licq::UserId& userId)
686 : myUserId(userId)
687 {
688 {
689 Licq::OwnerReadGuard o(gIcqProtocol.ownerId());
690 myName = o->getAlias();
691 m_nSession = o->Port();
692 }
693
694 m_pChatClient = NULL;
695 m_bThreadCreated = false;
696
697 pthread_mutex_init(&thread_list_mutex, NULL);
698
699 pthread_mutex_lock(&cmList_mutex);
700 cmList.push_back(this);
701 pthread_mutex_unlock(&cmList_mutex);
702 }
703
init(const string & fontFamily,unsigned char fontEncoding,unsigned char fontStyle,unsigned short fontSize,bool fontBold,bool fontItalic,bool fontUnderline,bool fontStrikeOut,int fr,int fg,int fb,int br,int bg,int bb)704 void ChatManager::init(const string& fontFamily, unsigned char fontEncoding,
705 unsigned char fontStyle, unsigned short fontSize, bool fontBold, bool fontItalic,
706 bool fontUnderline, bool fontStrikeOut, int fr, int fg, int fb, int br, int bg, int bb)
707 {
708 m_nFontFace = FONT_PLAIN;
709 if (fontBold) m_nFontFace |= FONT_BOLD;
710 if (fontItalic) m_nFontFace |= FONT_ITALIC;
711 if (fontUnderline) m_nFontFace |= FONT_UNDERLINE;
712 if (fontStrikeOut) m_nFontFace |= FONT_STRIKEOUT;
713 myFontFamily = fontFamily;
714 m_nFontEncoding = fontEncoding;
715 m_nFontStyle = fontStyle;
716 m_nFontSize = fontSize;
717 m_nColorFore[0] = fr;
718 m_nColorFore[1] = fg;
719 m_nColorFore[2] = fb;
720 m_nColorBack[0] = br;
721 m_nColorBack[1] = bg;
722 m_nColorBack[2] = bb;
723 m_bFocus = true;
724 m_bSleep = false;
725 }
726
727
728 //-----ChatManager::StartChatServer-----------------------------------------
StartChatServer()729 bool ChatManager::StartChatServer()
730 {
731 if (gDaemon.StartTCPServer(&chatServer) == -1)
732 {
733 gLog.warning(tr("No more ports available, add more or close open chat/file sessions."));
734 return false;
735 }
736
737 // Add the server to the sock manager
738 sockman.AddSocket(&chatServer);
739 sockman.DropSocket(&chatServer);
740
741 return true;
742 }
743
744
745
StartAsServer()746 bool ChatManager::StartAsServer()
747 {
748 if (!StartChatServer())
749 {
750 PushChatEvent(new IcqChatEvent(CHAT_ERRORxBIND, NULL));
751 return false;
752 }
753
754 // Create the socket manager thread
755 if (pthread_create(&thread_chat, NULL, &ChatManager_tep, this) == -1)
756 {
757 PushChatEvent(new IcqChatEvent(CHAT_ERRORxRESOURCES, NULL));
758 return false;
759 }
760
761 m_bThreadCreated = true;
762
763 return true;
764 }
765
766
767 //-----ChatManager::StartAsClient-------------------------------------------
StartAsClient(unsigned short nPort)768 void ChatManager::StartAsClient(unsigned short nPort)
769 {
770 if (!StartChatServer()) return;
771
772 {
773 UserReadGuard u(myUserId);
774 if (!u.isLocked())
775 return;
776 m_pChatClient = new ChatClient(*u);
777 m_pChatClient->m_nPort = nPort;
778 }
779
780 // Create the socket manager thread
781 if (pthread_create(&thread_chat, NULL, &ChatManager_tep, this) == -1)
782 {
783 PushChatEvent(new IcqChatEvent(CHAT_ERRORxRESOURCES, NULL));
784 return;
785 }
786 }
787
788
789 //-----ChatManager::ConnectToChat-------------------------------------------
ConnectToChat(ChatClient * c)790 bool ChatManager::ConnectToChat(ChatClient *c)
791 {
792 ChatUser* u = new ChatUser;
793 u->m_pClient = c;
794 u->m_pClient->m_nSession = m_nSession;
795
796 char szUin[24];
797 sprintf(szUin, "%lu", c->myUin);
798 u->myUserId = Licq::UserId(myUserId, szUin);
799
800 bool bSendIntIp = false;
801 bool bTryDirect = true;
802 bool bResult = false;
803
804 {
805 UserReadGuard temp_user(u->myUserId);
806 if (temp_user.isLocked())
807 {
808 bSendIntIp = temp_user->SendIntIp();
809 bTryDirect = temp_user->Version() <= 6 || temp_user->directMode();
810 }
811 }
812
813 bool bSuccess = false;
814 if (bTryDirect)
815 {
816 gLog.info(tr("Chat: Connecting to server."));
817 bSuccess = gIcqProtocol.OpenConnectionToUser("chat", c->m_nIp, c->m_nIntIp,
818 &u->sock, c->m_nPort, bSendIntIp);
819 }
820
821 if (!bSuccess)
822 {
823 unsigned long nIp;
824 {
825 Licq::OwnerReadGuard o(gIcqProtocol.ownerId());
826 nIp = bSendIntIp ? o->IntIp() : o->Ip();
827 }
828
829 // try reverse connect
830 int nId = gIcqProtocol.requestReverseConnection(u->myUserId, c->m_nSession,
831 nIp, LocalPort(), c->m_nPort);
832 if (nId != -1)
833 {
834 pthread_t t;
835 struct SChatReverseConnectInfo *r = new struct SChatReverseConnectInfo;
836 r->nId = nId;
837 r->u = u;
838 r->m = this;
839 r->bTryDirect = !bTryDirect;
840 pthread_mutex_lock(&thread_list_mutex);
841 pthread_create(&t, NULL, ChatWaitForSignal_tep, r);
842 waitingThreads.push_back(t);
843 pthread_mutex_unlock(&thread_list_mutex);
844 bResult = true;
845 }
846 else
847 {
848 delete u->m_pClient;
849 delete u;
850 }
851 }
852 else
853 {
854 chatUsers.push_back(u);
855 bResult = SendChatHandshake(u);
856 }
857
858 return bResult;
859 }
860
SendChatHandshake(ChatUser * u)861 bool ChatManager::SendChatHandshake(ChatUser* u)
862 {
863 ChatClient* c = u->m_pClient;
864 char szUin[24];
865 sprintf(szUin, "%lu", c->myUin);
866 Licq::UserId userId(myUserId, szUin);
867
868 gLog.info(tr("Chat: Shaking hands [v%d]."), IcqProtocol::dcVersionToUse(c->m_nVersion));
869
870 // Send handshake packet:
871 if (!IcqProtocol::handshake_Send(&u->sock, userId, LocalPort(),
872 IcqProtocol::dcVersionToUse(c->m_nVersion), false))
873 return false;
874
875 // Send color packet
876 CPChat_Color p_color(myName, LocalPort(),
877 m_nColorFore[0], m_nColorFore[1], m_nColorFore[2],
878 m_nColorBack[0], m_nColorBack[1], m_nColorBack[2]);
879 u->sock.send(*p_color.getBuffer());
880
881 gLog.info(tr("Chat: Waiting for color/font response."));
882
883 u->state = CHAT_STATE_WAITxFORxCOLORxFONT;
884
885 sockman.AddSocket(&u->sock);
886 sockman.DropSocket(&u->sock);
887
888 return true;
889 }
890
891
892 //-----ChatManager::AcceptReverseConnection---------------------------------
AcceptReverseConnection(DcSocket * s)893 void ChatManager::AcceptReverseConnection(DcSocket* s)
894 {
895 ChatUser* u = new ChatUser;
896 u->sock.TransferConnectionFrom(*s);
897
898 u->m_pClient = new ChatClient();
899 u->m_pClient->m_nVersion = s->Version();
900 u->m_pClient->myUin = atol(s->userId().accountId().c_str());
901 u->m_pClient->m_nIp = s->getRemoteIpInt();
902 u->m_pClient->m_nIntIp = s->getRemoteIpInt();
903 u->m_pClient->m_nMode = MODE_DIRECT;
904 u->m_pClient->m_nHandshake = 0x65;
905
906 // These will still need to be set
907 u->m_pClient->m_nPort = 0;
908 u->m_pClient->m_nSession = 0;
909
910 u->myUserId = s->userId();
911 u->state = CHAT_STATE_WAITxFORxCOLOR;
912 chatUsers.push_back(u);
913
914 // Reload the socket information
915 sockman.AddSocket(&u->sock);
916 sockman.DropSocket(&u->sock);
917 myThreadPipe.putChar('R');
918
919 gLog.info(tr("Chat: Received reverse connection."));
920 }
921
922
923 //-----ChatManager::FindChatUser--------------------------------------------
FindChatUser(int sd)924 ChatUser* ChatManager::FindChatUser(int sd)
925 {
926 // Find the right user (possible race condition, but we ignore it for now)
927 ChatUserList::iterator iter;
928 for (iter = chatUsers.begin(); iter != chatUsers.end(); ++iter)
929 if ( (*iter)->sock.Descriptor() == sd) break;
930
931 if (iter == chatUsers.end())
932 return NULL;
933
934 return *iter;
935 }
936
937
938 //-----ChatManager::ProcessPacket-------------------------------------------
ProcessPacket(ChatUser * u)939 bool ChatManager::ProcessPacket(ChatUser* u)
940 {
941 if (!u->sock.RecvPacket())
942 {
943 if (u->sock.Error() == 0)
944 gLog.info(tr("Chat: Remote end disconnected."));
945 else
946 gLog.info(tr("Chat: Lost remote end: %s"), u->sock.errorStr().c_str());
947 return false;
948 }
949
950 if (!u->sock.RecvBufferFull()) return true;
951
952 switch(u->state)
953 {
954 case CHAT_STATE_HANDSHAKE:
955 {
956 CBuffer handshake = u->sock.RecvBuffer();
957 // get the handshake packet
958 if (!gIcqProtocol.Handshake_Recv(&u->sock, LocalPort(), false, true))
959 {
960 gLog.warning(tr("Chat: Bad handshake."));
961 return false;
962 }
963 switch (u->sock.Version())
964 {
965 case 1:
966 case 2:
967 case 3:
968 u->m_pClient->LoadFromHandshake_v2(handshake);
969 break;
970 case 4:
971 case 5:
972 u->m_pClient->LoadFromHandshake_v4(handshake);
973 break;
974 case 6:
975 u->m_pClient->LoadFromHandshake_v6(handshake);
976 break;
977 case 7:
978 case 8:
979 u->m_pClient->LoadFromHandshake_v7(handshake);
980 break;
981 }
982 gLog.info(tr("Chat: Received handshake from %ld [v%ld]."),
983 u->m_pClient->myUin, u->sock.Version());
984 char szUin[24];
985 sprintf(szUin, "%lu", u->m_pClient->myUin);
986 u->myUserId = Licq::UserId(myUserId, szUin);
987
988 bool bFound = false;
989 {
990 pthread_mutex_lock(&gIcqProtocol.mutex_reverseconnect);
991 std::list<CReverseConnectToUserData *>::iterator iter;
992 for (iter = gIcqProtocol.m_lReverseConnect.begin();
993 iter != gIcqProtocol.m_lReverseConnect.end(); ++iter)
994 {
995 if ((*iter)->myIdString == u->userId().accountId())
996 {
997 bFound = true;
998 (*iter)->bSuccess = true;
999 (*iter)->bFinished = true;
1000 u->m_pClient->m_nSession = (*iter)->nData;
1001 u->m_pClient->m_nPort = (*iter)->nPort;
1002 pthread_cond_broadcast(&gIcqProtocol.cond_reverseconnect_done);
1003 break;
1004 }
1005 }
1006 pthread_mutex_unlock(&gIcqProtocol.mutex_reverseconnect);
1007 }
1008
1009 if (bFound)
1010 {
1011 // Send color packet
1012 CPChat_Color p_color(myName, LocalPort(),
1013 m_nColorFore[0], m_nColorFore[1], m_nColorFore[2],
1014 m_nColorBack[0], m_nColorBack[1], m_nColorBack[2]);
1015 u->sock.send(*p_color.getBuffer());
1016
1017 gLog.info(tr("Chat: Waiting for color/font response."));
1018
1019 u->state = CHAT_STATE_WAITxFORxCOLORxFONT;
1020 }
1021 else
1022 {
1023 u->state = CHAT_STATE_WAITxFORxCOLOR;
1024 }
1025 break;
1026 }
1027
1028 case CHAT_STATE_WAITxFORxCOLOR: // we just received the color packet
1029 {
1030 gLog.info(tr("Chat: Received color packet."));
1031
1032 CPChat_Color pin(u->sock.RecvBuffer());
1033
1034 u->myName = pin.name();
1035 // Fill in the remaining fields in the client structure
1036 u->m_pClient->m_nPort = pin.Port();
1037 u->m_pClient->m_nSession = m_nSession;
1038
1039 // set up the remote colors
1040 u->colorFore[0] = pin.ColorForeRed();
1041 u->colorFore[1] = pin.ColorForeGreen();
1042 u->colorFore[2] = pin.ColorForeBlue();
1043 u->colorBack[0] = pin.ColorBackRed();
1044 u->colorBack[1] = pin.ColorBackGreen();
1045 u->colorBack[2] = pin.ColorBackBlue();
1046
1047 // Send the response
1048 ChatClientPList l;
1049 ChatUserList::iterator iter;
1050 for (iter = chatUsers.begin(); iter != chatUsers.end(); ++iter)
1051 {
1052 // Skip this guys client info and anybody we haven't connected to yet
1053 if ((*iter)->myUserId == u->myUserId || (*iter)->m_pClient->myUin < 1000)
1054 continue;
1055 l.push_back((*iter)->m_pClient);
1056 }
1057
1058 CPChat_ColorFont p_colorfont(myName, LocalPort(), m_nSession,
1059 m_nColorFore[0], m_nColorFore[1], m_nColorFore[2],
1060 m_nColorBack[0], m_nColorBack[1], m_nColorBack[2],
1061 m_nFontSize, m_nFontFace & FONT_BOLD, m_nFontFace & FONT_ITALIC,
1062 m_nFontFace & FONT_UNDERLINE, m_nFontFace & FONT_STRIKEOUT,
1063 myFontFamily, m_nFontEncoding, m_nFontStyle, l);
1064 if (!u->sock.send(*p_colorfont.getBuffer()))
1065 {
1066 gLog.error(tr("Chat: Send error (color/font packet): %s"), u->sock.errorStr().c_str());
1067 return false;
1068 }
1069 u->state = CHAT_STATE_WAITxFORxFONT;
1070 break;
1071 }
1072
1073 case CHAT_STATE_WAITxFORxFONT:
1074 {
1075 gLog.info(tr("Chat: Received font packet."));
1076 CPChat_Font pin(u->sock.RecvBuffer());
1077
1078 // just received the font reply
1079 m_nSession = pin.Session();
1080 u->fontSize = pin.FontSize();
1081 u->fontFace = pin.FontFace();
1082 u->myFontFamily = pin.fontFamily();
1083 u->fontEncoding = pin.FontEncoding();
1084 u->fontStyle = pin.FontStyle();
1085
1086 u->state = CHAT_STATE_CONNECTED;
1087 PushChatEvent(new IcqChatEvent(CHAT_CONNECTION, u));
1088 break;
1089 }
1090
1091 case CHAT_STATE_WAITxFORxCOLORxFONT:
1092 {
1093 gLog.info(tr("Chat: Received color/font packet."));
1094
1095 CPChat_ColorFont pin(u->sock.RecvBuffer());
1096 char szUin[24];
1097 sprintf(szUin, "%lu", pin.uin());
1098 u->myUserId = Licq::UserId(myUserId, szUin);
1099 // m_nSession = pin.Session();
1100
1101 // just received the color/font packet
1102 u->myName = pin.name();
1103
1104 // set up the remote colors
1105 u->colorFore[0] = pin.ColorForeRed();
1106 u->colorFore[1] = pin.ColorForeGreen();
1107 u->colorFore[2] = pin.ColorForeBlue();
1108 u->colorBack[0] = pin.ColorBackRed();
1109 u->colorBack[1] = pin.ColorBackGreen();
1110 u->colorBack[2] = pin.ColorBackBlue();
1111
1112 // set up the remote font
1113 // m_nSession = pin.Session();
1114 u->fontSize = pin.FontSize();
1115 u->fontFace = pin.FontFace();
1116 u->myFontFamily = pin.fontFamily();
1117 u->fontEncoding = pin.FontEncoding();
1118 u->fontStyle = pin.FontStyle();
1119
1120 // Parse the multiusers list
1121 if (pin.ChatClients().size() > 0)
1122 {
1123 gLog.info(tr("Chat: Joined multiparty (%d people)."),
1124 int(pin.ChatClients().size() + 1));
1125 ChatClientList::iterator iter;
1126 for (iter = pin.ChatClients().begin(); iter != pin.ChatClients().end(); ++iter)
1127 {
1128 char szUin[24];
1129 sprintf(szUin, "%lu", iter->myUin);
1130 Licq::UserId userId(myUserId, szUin);
1131
1132 ChatUserList::iterator iter2;
1133 for (iter2 = chatUsers.begin(); iter2 != chatUsers.end(); iter2++)
1134 {
1135 if ((*iter2)->myUserId == userId)
1136 break;
1137 }
1138 if (iter2 != chatUsers.end()) continue;
1139 // Connect to this user
1140 ChatClient *p = new ChatClient(*iter);
1141 ConnectToChat(p);
1142 }
1143 }
1144
1145 // send the reply (font packet)
1146 CPChat_Font p_font(LocalPort(), m_nSession,
1147 m_nFontSize, m_nFontFace & FONT_BOLD, m_nFontFace & FONT_ITALIC,
1148 m_nFontFace & FONT_UNDERLINE, m_nFontFace & FONT_STRIKEOUT,
1149 myFontFamily, m_nFontEncoding, m_nFontStyle);
1150 if (!u->sock.send(*p_font.getBuffer()))
1151 {
1152 gLog.error(tr("Chat: Send error (font packet): %s"), u->sock.errorStr().c_str());
1153 return false;
1154 }
1155
1156 // now we are done with the handshaking
1157 u->state = CHAT_STATE_CONNECTED;
1158 PushChatEvent(new IcqChatEvent(CHAT_CONNECTION, u));
1159 break;
1160 }
1161
1162 case CHAT_STATE_CONNECTED:
1163 default:
1164 gLog.error(tr("Internal error: ChatManager::ProcessPacket(), invalid state (%d)."),
1165 u->state);
1166 break;
1167
1168 } // switch
1169
1170 u->sock.ClearRecvBuffer();
1171
1172 return true;
1173 }
1174
1175
1176 //-----ChatManager::PopChatEvent--------------------------------------------
PopChatEvent()1177 IcqChatEvent *ChatManager::PopChatEvent()
1178 {
1179 if (chatEvents.empty()) return NULL;
1180
1181 IcqChatEvent *e = chatEvents.front();
1182 chatEvents.pop_front();
1183
1184 // Lock the user, will be unlocked in the event destructor
1185 if (e->m_pUser)
1186 {
1187 pthread_mutex_lock(&dynamic_cast<ChatUser*>(e->m_pUser)->mutex);
1188 e->m_bLocked = true;
1189 }
1190
1191 return e;
1192 }
1193
1194
1195 //-----ChatManager::PushChatEvent-------------------------------------------
PushChatEvent(IcqChatEvent * e)1196 void ChatManager::PushChatEvent(IcqChatEvent *e)
1197 {
1198 chatEvents.push_back(e);
1199 myEventsPipe.putChar('*');
1200 }
1201
ConnectedUsers() const1202 unsigned short ChatManager::ConnectedUsers() const
1203 {
1204 return chatUsers.size();
1205 }
1206
LocalPort() const1207 unsigned short ChatManager::LocalPort() const
1208 {
1209 return chatServer.getLocalPort();
1210 }
1211
Pipe()1212 int ChatManager::Pipe()
1213 {
1214 return myEventsPipe.getReadFd();
1215 }
1216
1217 //-----ChatManager::ProcessRaw----------------------------------------------
ProcessRaw(ChatUser * u)1218 bool ChatManager::ProcessRaw(ChatUser* u)
1219 {
1220 Licq::Buffer buf;
1221 if (!u->sock.receive(buf))
1222 {
1223 if (u->sock.Error() == 0)
1224 gLog.info(tr("Chat: Remote end disconnected."));
1225 else
1226 gLog.info(tr("Chat: Lost remote end: %s"), u->sock.errorStr().c_str());
1227 return false;
1228 }
1229
1230 while (!buf.End())
1231 u->chatQueue.push_back(buf.unpackUInt8());
1232
1233 if (u->sock.Version() >= 6)
1234 return ProcessRaw_v6(u);
1235 else
1236 return ProcessRaw_v2(u);
1237 }
1238
1239
ProcessRaw_v2(ChatUser * u)1240 bool ChatManager::ProcessRaw_v2(ChatUser* u)
1241 {
1242 char chatChar;
1243 while (u->chatQueue.size() > 0)
1244 {
1245 chatChar = *u->chatQueue.begin(); // first character in queue (not dequeued)
1246 switch (chatChar)
1247 {
1248 case CHAT_NEWLINE: // new line
1249 // add to irc window
1250 PushChatEvent(new IcqChatEvent(CHAT_NEWLINE, u,
1251 gTranslator.toUtf8(u->myLinebuf, userEncoding(u))));
1252 u->myLinebuf.clear();
1253 u->chatQueue.pop_front();
1254 break;
1255
1256 case CHAT_BEEP: // beep
1257 {
1258 PushChatEvent(new IcqChatEvent(CHAT_BEEP, u));
1259 u->chatQueue.pop_front();
1260 break;
1261 }
1262
1263 case CHAT_LAUGH: // laugh
1264 {
1265 PushChatEvent(new IcqChatEvent(CHAT_LAUGH, u));
1266 u->chatQueue.pop_front();
1267 break;
1268 }
1269
1270 case CHAT_BACKSPACE: // backspace
1271 {
1272 if (u->myLinebuf.size() > 0)
1273 u->myLinebuf.erase(u->myLinebuf.size()-1);
1274 PushChatEvent(new IcqChatEvent(CHAT_BACKSPACE, u));
1275 u->chatQueue.pop_front();
1276 break;
1277 }
1278
1279 case CHAT_COLORxFG: // change foreground color
1280 {
1281 if (u->chatQueue.size() < 5) return true;
1282 u->colorFore[0] = u->chatQueue[1];
1283 u->colorFore[1] = u->chatQueue[2];
1284 u->colorFore[2] = u->chatQueue[3];
1285 for (unsigned short i = 0; i < 5; i++)
1286 u->chatQueue.pop_front();
1287
1288 PushChatEvent(new IcqChatEvent(CHAT_COLORxFG, u));
1289 break;
1290 }
1291
1292 case CHAT_COLORxBG: // change background color
1293 {
1294 if (u->chatQueue.size() < 5) return true;
1295 u->colorBack[0] = u->chatQueue[1];
1296 u->colorBack[1] = u->chatQueue[2];
1297 u->colorBack[2] = u->chatQueue[3];
1298 for (unsigned short i = 0; i < 5; i++)
1299 u->chatQueue.pop_front();
1300
1301 PushChatEvent(new IcqChatEvent(CHAT_COLORxBG, u));
1302 break;
1303 }
1304 case CHAT_FONTxFAMILY: // change font type
1305 {
1306 if (u->chatQueue.size() < 3) return true;
1307 unsigned short sizeFontName;
1308 sizeFontName = u->chatQueue[1] | (u->chatQueue[2] << 8);
1309 if (u->chatQueue.size() < (unsigned long)(sizeFontName + 2 + 3)) return true;
1310 u->myFontFamily = gTranslator.toUtf8(string((const char*)(&u->chatQueue[3]), sizeFontName), userEncoding(u));
1311 u->fontEncoding = u->chatQueue[sizeFontName + 3];
1312 u->fontStyle = u->chatQueue[sizeFontName + 4];
1313
1314 // Dequeue all characters
1315 for (unsigned short i = 0; i < 3 + sizeFontName + 2; i++)
1316 u->chatQueue.pop_front();
1317
1318 PushChatEvent(new IcqChatEvent(CHAT_FONTxFAMILY, u));
1319 break;
1320 }
1321
1322 case CHAT_FONTxFACE: // change font style
1323 {
1324 if (u->chatQueue.size() < 5) return true;
1325 unsigned long styleFont;
1326 styleFont = u->chatQueue[1] | (u->chatQueue[2] << 8) |
1327 (u->chatQueue[3] << 16) | (u->chatQueue[4] << 24);
1328
1329 u->fontFace = styleFont;
1330
1331 // Dequeue all characters
1332 for (unsigned short i = 0; i < 5; i++)
1333 u->chatQueue.pop_front();
1334
1335 PushChatEvent(new IcqChatEvent(CHAT_FONTxFACE, u));
1336 break;
1337 }
1338
1339 case CHAT_FONTxSIZE: // change font size
1340 {
1341 if (u->chatQueue.size() < 5) return true;
1342 unsigned long sizeFont;
1343 sizeFont = u->chatQueue[1] | (u->chatQueue[2] << 8) |
1344 (u->chatQueue[3] << 16) | (u->chatQueue[4] << 24);
1345 u->fontSize = sizeFont;
1346
1347 // Dequeue all characters
1348 for (unsigned short i = 0; i < 5; i++)
1349 u->chatQueue.pop_front();
1350
1351 PushChatEvent(new IcqChatEvent(CHAT_FONTxSIZE, u));
1352 break;
1353 }
1354
1355 case CHAT_FOCUSxIN:
1356 {
1357 u->focus = true;
1358 PushChatEvent(new IcqChatEvent(CHAT_FOCUSxIN, u));
1359 u->chatQueue.pop_front();
1360 break;
1361 }
1362
1363 case CHAT_FOCUSxOUT:
1364 {
1365 u->focus = false;
1366 PushChatEvent(new IcqChatEvent(CHAT_FOCUSxOUT, u));
1367 u->chatQueue.pop_front();
1368 break;
1369 }
1370
1371 case CHAT_SLEEPxOFF:
1372 {
1373 u->sleep = false;
1374 PushChatEvent(new IcqChatEvent(CHAT_SLEEPxOFF, u));
1375 u->chatQueue.pop_front();
1376 break;
1377 }
1378
1379 case CHAT_SLEEPxON:
1380 {
1381 u->sleep = true;
1382 PushChatEvent(new IcqChatEvent(CHAT_SLEEPxON, u));
1383 u->chatQueue.pop_front();
1384 break;
1385 }
1386
1387 case CHAT_KICK:
1388 {
1389 if (u->chatQueue.size() < 4) return true;
1390 u->nToKick = u->chatQueue[0] | (u->chatQueue[1] << 8) |
1391 (u->chatQueue[2] << 16) | (u->chatQueue[3] << 24);
1392
1393 // Dequeue all the characters
1394 for (unsigned short i = 0; i < 4; i++)
1395 u->chatQueue.pop_front();
1396
1397 PushChatEvent(new IcqChatEvent(CHAT_KICK, u));
1398 break;
1399 }
1400
1401 case CHAT_KICKxYES:
1402 {
1403 if (u->chatQueue.size() < 4) return true;
1404 unsigned long nUin = u->chatQueue[0] | (u->chatQueue[1] << 8) |
1405 (u->chatQueue[2] << 16) | (u->chatQueue[3] << 24);
1406
1407 // Deque all the characters
1408 for (unsigned short i = 0; i < 4; i++)
1409 u->chatQueue.pop_front();
1410
1411 // Find the person that we receive the yes vote
1412 VoteInfoList::iterator iter;
1413 for (iter = voteInfo.begin(); iter != voteInfo.end(); ++iter)
1414 {
1415 if ((*iter)->nUin == nUin)
1416 break;
1417 }
1418
1419 if (iter == voteInfo.end()) return true;
1420
1421 (*iter)->nYes++;
1422
1423 // Is there a majority?
1424 unsigned short nMajority = (*iter)->nNumUsers / 2;
1425 nMajority++;
1426 if ((*iter)->nYes == nMajority)
1427 FinishKickVote(iter, true);
1428 else if ((*iter)->nYes + (*iter)->nNo == (*iter)->nNumUsers)
1429 FinishKickVote(iter, false);
1430
1431
1432 PushChatEvent(new IcqChatEvent(CHAT_KICKxYES, u));
1433 break;
1434 }
1435
1436 case CHAT_KICKxNO:
1437 {
1438 if (u->chatQueue.size() < 4) return true;
1439 unsigned long nUin = u->chatQueue[0] | (u->chatQueue[1] << 8) |
1440 (u->chatQueue[2] << 16) | (u->chatQueue[3] << 24);
1441
1442 // Deque all the characters
1443 for (unsigned short i = 0; i < 4; i++)
1444 u->chatQueue.pop_front();
1445
1446 // Find the person that we receive the yes vote
1447 VoteInfoList::iterator iter;
1448 for (iter = voteInfo.begin(); iter != voteInfo.end(); ++iter)
1449 {
1450 if ((*iter)->nUin == nUin)
1451 break;
1452 }
1453
1454 if (iter == voteInfo.end()) return true;
1455
1456 (*iter)->nNo++;
1457
1458 // Is there a majority?
1459 unsigned short nMajority = (*iter)->nNumUsers / 2;
1460 nMajority++;
1461 if ((*iter)->nNo == nMajority)
1462 FinishKickVote(iter, false);
1463 else if ((*iter)->nYes + (*iter)->nNo == (*iter)->nNumUsers)
1464 FinishKickVote(iter, false);
1465
1466 PushChatEvent(new IcqChatEvent(CHAT_KICKxNO, u));
1467 break;
1468 }
1469
1470 case CHAT_KICKxPASS:
1471 {
1472 // The user here was kicked, close our connection to the user
1473 if (u->chatQueue.size() < 6) return true;
1474 unsigned long nUin = u->chatQueue[0] | (u->chatQueue[1] << 8) |
1475 (u->chatQueue[2] << 16) | (u->chatQueue[3] << 24);
1476 char id[16];
1477 snprintf(id, 16, "%lu", nUin);
1478 Licq::UserId userId(myUserId, id);
1479
1480 // Deque all the characters
1481 for (unsigned short i = 0; i < 6; i++)
1482 u->chatQueue.pop_front();
1483
1484 // Find the user and say bye-bye to him
1485 ChatUserList::iterator iter;
1486 for (iter = chatUsers.begin(); iter != chatUsers.end(); ++iter)
1487 {
1488 if ((*iter)->userId() == userId)
1489 break;
1490 }
1491
1492 if (iter == chatUsers.end()) return true;
1493
1494 CBuffer bye(4);
1495 SendBuffer(&bye, CHAT_DISCONNECTIONxKICKED, id, true);
1496
1497 CloseClient(*iter);
1498 break;
1499 }
1500
1501 case CHAT_KICKxFAIL:
1502 {
1503 if (u->chatQueue.size() < 6) return true;
1504
1505 for (unsigned short i = 0; i < 6; i++)
1506 u->chatQueue.pop_front();
1507
1508 PushChatEvent(new IcqChatEvent(CHAT_KICKxFAIL, u));
1509 break;
1510 }
1511
1512 case CHAT_KICKxYOU:
1513 {
1514 if (u->chatQueue.size() < 2) return true;
1515
1516 for (unsigned short i = 0; i < 2; i++)
1517 u->chatQueue.pop_front();
1518
1519 PushChatEvent(new IcqChatEvent(CHAT_KICKxYOU, u));
1520 break;
1521 }
1522
1523 case CHAT_DISCONNECTIONxKICKED:
1524 {
1525 PushChatEvent(new IcqChatEvent(CHAT_DISCONNECTIONxKICKED, u));
1526 u->chatQueue.pop_front();
1527 break;
1528 }
1529
1530 case CHAT_DISCONNECTION: // they will disconnect anyway
1531 {
1532 u->chatQueue.pop_front();
1533 break;
1534 }
1535
1536 default:
1537 {
1538 if (!iscntrl((int)(unsigned char)chatChar))
1539 {
1540 string tempStr;
1541 // If there are multiple chars, get them all
1542 do {
1543 tempStr += *u->chatQueue.begin();
1544 u->chatQueue.pop_front();
1545 } while (u->chatQueue.size() > 0 && !iscntrl((int)(unsigned char)(*u->chatQueue.begin())));
1546
1547 // Add to the users irc line buffer
1548 u->myLinebuf += tempStr;
1549 PushChatEvent(new IcqChatEvent(CHAT_CHARACTER, u, gTranslator.toUtf8(tempStr, userEncoding(u))));
1550 }
1551 else
1552 {
1553 u->chatQueue.pop_front();
1554 }
1555 break;
1556 }
1557 } // switch
1558 } // while
1559
1560 return true;
1561 }
1562
1563
ProcessRaw_v6(ChatUser * u)1564 bool ChatManager::ProcessRaw_v6(ChatUser* u)
1565 {
1566 char chatChar;
1567 unsigned long chatSize = 0;
1568 while (u->chatQueue.size() > 0)
1569 {
1570 chatChar = *u->chatQueue.begin(); // first character in queue (not dequeued)
1571 if (chatChar == 0)
1572 {
1573 // We need at least 6 chars
1574 if (u->chatQueue.size() < 6) return true;
1575 chatChar = u->chatQueue[1];
1576 chatSize = (u->chatQueue[2]) |
1577 (u->chatQueue[3] << 8) |
1578 (u->chatQueue[4] << 16) |
1579 (u->chatQueue[5] << 24);
1580
1581 if (u->chatQueue.size() < 6 + chatSize) return true;
1582 for (unsigned short i = 0; i < 6; i++)
1583 u->chatQueue.pop_front();
1584
1585 switch (chatChar)
1586 {
1587 case CHAT_BEEP: // beep
1588 {
1589 PushChatEvent(new IcqChatEvent(CHAT_BEEP, u));
1590 break;
1591 }
1592
1593 case CHAT_LAUGH: // laugh
1594 {
1595 PushChatEvent(new IcqChatEvent(CHAT_LAUGH, u));
1596 break;
1597 }
1598
1599 case CHAT_COLORxFG: // change foreground color
1600 {
1601 u->colorFore[0] = u->chatQueue[0];
1602 u->colorFore[1] = u->chatQueue[1];
1603 u->colorFore[2] = u->chatQueue[2];
1604
1605 PushChatEvent(new IcqChatEvent(CHAT_COLORxFG, u));
1606 break;
1607 }
1608
1609 case CHAT_COLORxBG: // change background color
1610 {
1611 u->colorBack[0] = u->chatQueue[0];
1612 u->colorBack[1] = u->chatQueue[1];
1613 u->colorBack[2] = u->chatQueue[2];
1614
1615 PushChatEvent(new IcqChatEvent(CHAT_COLORxBG, u));
1616 break;
1617 }
1618
1619 case CHAT_FONTxFAMILY: // change font type
1620 {
1621 unsigned short sizeFontName;
1622 sizeFontName = u->chatQueue[0] | (u->chatQueue[1] << 8);
1623 u->myFontFamily = gTranslator.toUtf8(string((const char*)(&u->chatQueue[2]), sizeFontName), userEncoding(u));
1624 u->fontEncoding = u->chatQueue[sizeFontName + 2];
1625 u->fontStyle = u->chatQueue[sizeFontName + 3];
1626
1627 PushChatEvent(new IcqChatEvent(CHAT_FONTxFAMILY, u));
1628 //the size includes the following character, so don't dequeue it
1629 chatSize--;
1630 break;
1631 }
1632
1633 case CHAT_FONTxFACE: // change font style
1634 {
1635 unsigned long styleFont;
1636 styleFont = u->chatQueue[0] | (u->chatQueue[1] << 8) |
1637 (u->chatQueue[2] << 16) | (u->chatQueue[3] << 24);
1638
1639 u->fontFace = styleFont;
1640
1641 PushChatEvent(new IcqChatEvent(CHAT_FONTxFACE, u));
1642 break;
1643 }
1644
1645 case CHAT_FONTxSIZE: // change font size
1646 {
1647 if (u->chatQueue.size() < 4) return true;
1648 unsigned long sizeFont;
1649 sizeFont = u->chatQueue[0] | (u->chatQueue[1] << 8) |
1650 (u->chatQueue[2] << 16) | (u->chatQueue[3] << 24);
1651 u->fontSize = sizeFont;
1652
1653 PushChatEvent(new IcqChatEvent(CHAT_FONTxSIZE, u));
1654 break;
1655 }
1656
1657 case CHAT_FOCUSxIN:
1658 {
1659 u->focus = true;
1660 PushChatEvent(new IcqChatEvent(CHAT_FOCUSxIN, u));
1661 break;
1662 }
1663
1664 case CHAT_FOCUSxOUT:
1665 {
1666 u->focus = false;
1667 PushChatEvent(new IcqChatEvent(CHAT_FOCUSxOUT, u));
1668 break;
1669 }
1670
1671 case CHAT_SLEEPxOFF:
1672 {
1673 u->sleep = false;
1674 PushChatEvent(new IcqChatEvent(CHAT_SLEEPxOFF, u));
1675 break;
1676 }
1677
1678 case CHAT_SLEEPxON:
1679 {
1680 u->sleep = true;
1681 PushChatEvent(new IcqChatEvent(CHAT_SLEEPxON, u));
1682 break;
1683 }
1684
1685 case CHAT_KICK:
1686 {
1687 if (u->chatQueue.size() < 4) return true;
1688 unsigned long nUinToKick;
1689 nUinToKick = u->chatQueue[0] | (u->chatQueue[1] << 8) |
1690 (u->chatQueue[2] << 16) | (u->chatQueue[3] << 24);
1691 u->nToKick = nUinToKick;
1692
1693 PushChatEvent(new IcqChatEvent(CHAT_KICK, u));
1694 break;
1695 }
1696
1697 case CHAT_KICKxYES:
1698 {
1699 if (u->chatQueue.size() < 4) return true;
1700 unsigned long nUin = u->chatQueue[0] | (u->chatQueue[1] << 8) |
1701 (u->chatQueue[2] << 16) | (u->chatQueue[3] << 24);
1702
1703 // Find the person that we received the yes vote for
1704 VoteInfoList::iterator iter;
1705 for (iter = voteInfo.begin(); iter != voteInfo.end(); ++iter)
1706 {
1707 if ((*iter)->nUin == nUin)
1708 break;
1709 }
1710
1711 if (iter == voteInfo.end()) return true;
1712
1713 (*iter)->nYes++;
1714
1715 // Is there a majority?
1716 unsigned short nMajority = (*iter)->nNumUsers / 2;
1717 nMajority++;
1718 if ((*iter)->nYes == nMajority)
1719 FinishKickVote(iter, true);
1720 else if (((*iter)->nYes + (*iter)->nNo) == (*iter)->nNumUsers)
1721 FinishKickVote(iter, false);
1722
1723 PushChatEvent(new IcqChatEvent(CHAT_KICKxYES, u));
1724 break;
1725 }
1726
1727 case CHAT_KICKxNO:
1728 {
1729 if (u->chatQueue.size() < 4) return true;
1730 unsigned long nUin = u->chatQueue[0] | (u->chatQueue[1] << 8) |
1731 (u->chatQueue[2] << 16) | (u->chatQueue[3] << 24);
1732
1733 // Find the person that we received the no vote for
1734 VoteInfoList::iterator iter;
1735 for (iter = voteInfo.begin(); iter != voteInfo.end(); ++iter)
1736 {
1737 if ((*iter)->nUin == nUin)
1738 break;
1739 }
1740
1741 if (iter == voteInfo.end()) return true;
1742
1743 (*iter)->nNo++;
1744
1745 // Is there a majority?
1746 unsigned short nMajority = (*iter)->nNumUsers / 2;
1747 nMajority++;
1748 if ((*iter)->nNo == nMajority)
1749 FinishKickVote(iter, false);
1750 else if (((*iter)->nYes + (*iter)->nNo) == (*iter)->nNumUsers)
1751 FinishKickVote(iter, false);
1752
1753 PushChatEvent(new IcqChatEvent(CHAT_KICKxNO, u));
1754 break;
1755 }
1756
1757 case CHAT_KICKxPASS:
1758 {
1759 // The user here was kicked, close our connection to the user
1760 if (u->chatQueue.size() < 6) return true;
1761 unsigned long nUin = u->chatQueue[0] | (u->chatQueue[1] << 8) |
1762 (u->chatQueue[2] << 16) | (u->chatQueue[3] << 24);
1763 char id[16];
1764 snprintf(id, 16, "%lu", nUin);
1765 Licq::UserId userId(myUserId, id);
1766
1767 // Find the user and say bye-bye to him
1768 ChatUserList::iterator iter;
1769 for (iter = chatUsers.begin(); iter != chatUsers.end(); ++iter)
1770 {
1771 if ((*iter)->userId() == userId)
1772 break;
1773 }
1774
1775 if (iter == chatUsers.end()) return true;
1776
1777 CBuffer bye(4);
1778 SendBuffer(&bye, CHAT_DISCONNECTIONxKICKED, id, true);
1779
1780 CloseClient(*iter);
1781 break;
1782 }
1783
1784 case CHAT_KICKxFAIL:
1785 {
1786 // The user was not kicked, a majority wasn't received
1787 PushChatEvent(new IcqChatEvent(CHAT_KICKxFAIL, u));
1788 break;
1789 }
1790
1791 case CHAT_KICKxYOU: // we were kicked
1792 {
1793 PushChatEvent(new IcqChatEvent(CHAT_KICKxYOU, u));
1794 break;
1795 }
1796
1797 case CHAT_DISCONNECTIONxKICKED: // they disconnected cuz we were kicked
1798 {
1799 PushChatEvent(new IcqChatEvent(CHAT_DISCONNECTIONxKICKED, u));
1800 break;
1801 }
1802
1803 case CHAT_DISCONNECTION: // they will disconnect anyway
1804 {
1805 break;
1806 }
1807
1808 default:
1809 {
1810 gLog.unknown(tr("Chat: Unknown chat command (%02X)"), chatChar);
1811 break;
1812 }
1813
1814 } // switch
1815
1816 // dequeue all characters
1817 for (unsigned short i = 0; i < chatSize; i++)
1818 u->chatQueue.pop_front();
1819
1820 } // if
1821
1822 else // not a command
1823 {
1824 switch (chatChar)
1825 {
1826 case CHAT_NEWLINE: // new line
1827 // add to irc window
1828 PushChatEvent(new IcqChatEvent(CHAT_NEWLINE, u, gTranslator.toUtf8(u->myLinebuf, userEncoding(u))));
1829 u->myLinebuf.clear();
1830 u->chatQueue.pop_front();
1831 break;
1832
1833 case CHAT_BACKSPACE: // backspace
1834 {
1835 if (u->myLinebuf.size() > 0)
1836 u->myLinebuf.erase(u->myLinebuf.size() - 1);
1837 PushChatEvent(new IcqChatEvent(CHAT_BACKSPACE, u));
1838 u->chatQueue.pop_front();
1839 break;
1840 }
1841
1842 default:
1843 {
1844 if (!iscntrl((int)(unsigned char)chatChar))
1845 {
1846 string tempStr;
1847 // If there are multiple chars, get them all
1848 do {
1849 tempStr += *u->chatQueue.begin();
1850 u->chatQueue.pop_front();
1851 } while (u->chatQueue.size() > 0 && !iscntrl((int)(unsigned char)(*u->chatQueue.begin())));
1852
1853 // Add to the users irc line buffer
1854 u->myLinebuf += tempStr;
1855 PushChatEvent(new IcqChatEvent(CHAT_CHARACTER, u, gTranslator.toUtf8(tempStr, userEncoding(u))));
1856 }
1857 else
1858 {
1859 u->chatQueue.pop_front();
1860 }
1861 break;
1862 }
1863 }
1864 }
1865
1866 }
1867
1868
1869 return true;
1870 }
1871
1872
1873 //-----ChatManager::SendPacket----------------------------------------------
1874 /*
1875 void ChatManager::SendPacket(CPacket *p)
1876 {
1877 SendBuffer(p->getBuffer());
1878 }
1879 */
1880
1881 //-----ChatManager::SendBuffer----------------------------------------------
SendBuffer(CBuffer * b,unsigned char cmd,const char * id,bool bNotIter)1882 void ChatManager::SendBuffer(CBuffer *b, unsigned char cmd,
1883 const char* id, bool bNotIter)
1884 {
1885 ChatUserList::iterator iter;
1886 ChatUserList::iterator u_iter;
1887 bool ok = false;
1888
1889 if (id != NULL)
1890 {
1891 Licq::UserId userId(myUserId, id);
1892 for (u_iter = chatUsers.begin(); u_iter != chatUsers.end(); ++u_iter)
1893 {
1894 if ((*u_iter)->userId() == userId)
1895 break;
1896 }
1897
1898 if (u_iter == chatUsers.end())
1899 return;
1900 }
1901
1902 while (!ok)
1903 {
1904 ok = true;
1905
1906 // Send it to every user
1907 if (id == NULL)
1908 {
1909 for (iter = chatUsers.begin(); iter != chatUsers.end(); ++iter)
1910 ok = SendBufferToClient(b, cmd, *iter);
1911 }
1912 else
1913 {
1914 // Send it to every user except _iter
1915 if (bNotIter)
1916 {
1917 for (iter = chatUsers.begin(); iter != u_iter; ++iter)
1918 ok = SendBufferToClient(b, cmd, *iter);
1919
1920 // Check to see if we are already at the end
1921 // And at the same time skip the user we don't want to send this to
1922 if (++iter == chatUsers.end()) return;
1923
1924 for (; iter != chatUsers.end(); ++iter)
1925 ok = SendBufferToClient(b, cmd, *iter);
1926 }
1927 // Send it only to _iter
1928 else
1929 ok = SendBufferToClient(b, cmd, *u_iter);
1930 }
1931 }
1932 }
1933
1934
SendBufferToClient(CBuffer * b,unsigned char cmd,ChatUser * u)1935 bool ChatManager::SendBufferToClient(CBuffer *b, unsigned char cmd, ChatUser* u)
1936 {
1937 CBuffer b_out(128);
1938
1939 // If the socket was closed, ignore the key event
1940 if (u->state != CHAT_STATE_CONNECTED || u->sock.Descriptor() == -1)
1941 return true;
1942
1943 if (u->sock.Version() >= 6)
1944 {
1945 b_out.PackChar(0);
1946 b_out.PackChar(cmd);
1947 //the change font command size includes the following character
1948 b_out.PackUnsignedLong(b->getDataSize() + ((cmd == CHAT_FONTxFAMILY)?1:0));
1949 b_out.Pack(b->getDataStart(), b->getDataSize());
1950 }
1951 else
1952 {
1953 b_out.PackChar(cmd);
1954 b_out.Pack(b->getDataStart(), b->getDataSize());
1955 }
1956
1957 if (!u->sock.send(b_out))
1958 {
1959 gLog.warning(tr("Chat: Send error: %s"), u->sock.errorStr().c_str());
1960 CloseClient(u);
1961 return false;
1962 }
1963
1964 b_out.setDataPosWrite(b_out.getDataStart());
1965 b_out.setDataPosRead(b_out.getDataStart());
1966
1967 return true;
1968 }
1969
1970
SendBuffer_Raw(CBuffer * b)1971 void ChatManager::SendBuffer_Raw(CBuffer *b)
1972 {
1973 ChatUserList::iterator iter;
1974 ChatUser* u = NULL;
1975 bool ok = false;
1976 while (!ok)
1977 {
1978 ok = true;
1979 for (iter = chatUsers.begin(); iter != chatUsers.end(); ++iter)
1980 {
1981 u = *iter;
1982
1983 // If the socket was closed, ignore the key event
1984 if (u->state != CHAT_STATE_CONNECTED || u->sock.Descriptor() == -1) continue;
1985
1986 if (!u->sock.send(*b))
1987 {
1988 gLog.warning(tr("Chat: Send error: %s"), u->sock.errorStr().c_str());
1989 CloseClient(u);
1990 ok = false;
1991 break;
1992 }
1993 }
1994 }
1995 }
1996
1997
SendNewline()1998 void ChatManager::SendNewline()
1999 {
2000 CBuffer buf(1);
2001 buf.PackChar(CHAT_NEWLINE);
2002 SendBuffer_Raw(&buf);
2003 }
2004
2005
SendBackspace()2006 void ChatManager::SendBackspace()
2007 {
2008 CBuffer buf(1);
2009 buf.PackChar(CHAT_BACKSPACE);
2010 SendBuffer_Raw(&buf);
2011 }
2012
2013
SendBeep()2014 void ChatManager::SendBeep()
2015 {
2016 CBuffer buf;
2017 SendBuffer(&buf, CHAT_BEEP);
2018 }
2019
2020
SendLaugh()2021 void ChatManager::SendLaugh()
2022 {
2023 CBuffer buf;
2024 SendBuffer(&buf, CHAT_LAUGH);
2025 }
2026
sendText(const string & text)2027 void ChatManager::sendText(const string& text)
2028 {
2029 CBuffer buf(text.size());
2030 buf.pack(gTranslator.fromUtf8(text, getEncoding(m_nFontEncoding)));
2031 SendBuffer_Raw(&buf);
2032 }
2033
2034
SendKick(const char * id)2035 void ChatManager::SendKick(const char* id)
2036 {
2037 unsigned long _nUin = strtoul(id, NULL, 10);
2038
2039 // Take care of the vote stuff now
2040 // The user we are kicking automatically is a no vote
2041 // And we are an automatic yes vote
2042 SVoteInfo *vote = new SVoteInfo;
2043 vote->nUin = _nUin;
2044 vote->nNumUsers = ConnectedUsers();
2045 vote->nYes = 1;
2046 vote->nNo = 1;
2047 voteInfo.push_back(vote);
2048
2049 // Send the packet to all connected clients except the one we are
2050 // requesting to kick
2051 CBuffer buf(4);
2052 buf.PackUnsignedLong(_nUin);
2053 SendBuffer(&buf, CHAT_KICK, id, true);
2054 }
2055
2056
SendKickNoVote(const char * id)2057 void ChatManager::SendKickNoVote(const char *id)
2058 {
2059 Licq::UserId userId(myUserId, id);
2060 unsigned long _nUin = strtoul(id, NULL, 10);
2061
2062 // Tell everyone that this user has been kicked
2063 CBuffer buf_TellAll(6);
2064 buf_TellAll.PackUnsignedLong(_nUin);
2065 buf_TellAll.PackChar(0x02);
2066 buf_TellAll.PackChar(0x01);
2067 SendBuffer(&buf_TellAll, CHAT_KICKxPASS, id, true);
2068
2069 // They don't know if there was a vote or not, they just see they've been kicked
2070 CBuffer buf(2);
2071 buf.PackChar(0x02);
2072 buf.PackChar(0x01);
2073 SendBuffer(&buf, CHAT_KICKxYOU, id, false);
2074
2075 // And close the connection to the kicked user
2076 ChatUserList::iterator iter;
2077 for (iter = chatUsers.begin(); iter != chatUsers.end(); ++iter)
2078 {
2079 if((*iter)->userId() == userId)
2080 break;
2081 }
2082
2083 if (iter == chatUsers.end()) return;
2084
2085 CBuffer bye(4);
2086 SendBuffer(&bye, CHAT_DISCONNECTIONxKICKED, id, false);
2087
2088 CloseClient(*iter);
2089 }
2090
2091
2092 // Only the person requesting the kick should receive it..
2093 // but what if more than one person has been asked to be kicked by
2094 // different people? It shouldn't send a reply to everyone..
2095 // Mirabilis ICQ just ignores it if it's not expecting it, i believe
SendVoteYes(unsigned long _nUin)2096 void ChatManager::SendVoteYes(unsigned long _nUin)
2097 {
2098 CBuffer buf(4);
2099 buf.PackUnsignedLong(_nUin);
2100 SendBuffer(&buf, CHAT_KICKxYES);
2101 }
2102
2103
SendVoteNo(unsigned long _nUin)2104 void ChatManager::SendVoteNo(unsigned long _nUin)
2105 {
2106 CBuffer buf(4);
2107 buf.PackUnsignedLong(_nUin);
2108 SendBuffer(&buf, CHAT_KICKxNO);
2109 }
2110
2111
FocusIn()2112 void ChatManager::FocusIn()
2113 {
2114 CBuffer buf;
2115 SendBuffer(&buf, CHAT_FOCUSxIN);
2116
2117 m_bFocus = true;
2118 }
2119
2120
FocusOut()2121 void ChatManager::FocusOut()
2122 {
2123 CBuffer buf;
2124 SendBuffer(&buf, CHAT_FOCUSxOUT);
2125
2126 m_bFocus = false;
2127 }
2128
2129
Sleep(bool s)2130 void ChatManager::Sleep(bool s)
2131 {
2132 CBuffer buf;
2133 SendBuffer(&buf, s ? CHAT_SLEEPxON : CHAT_SLEEPxOFF);
2134
2135 m_bSleep = s;
2136 }
2137
2138
changeFontFamily(const string & fontFamily,unsigned char enc,unsigned char style)2139 void ChatManager::changeFontFamily(const string& fontFamily, unsigned char enc,
2140 unsigned char style)
2141 {
2142 //CPChat_ChangeFontFamily p(fontFamily);
2143 //SendPacket(&p);
2144
2145 CBuffer buf(fontFamily.size() + 5);
2146 buf.PackString(fontFamily.c_str());
2147 buf.PackChar(enc);
2148 buf.PackChar(style);
2149 SendBuffer(&buf, CHAT_FONTxFAMILY);
2150
2151 myFontFamily = fontFamily;
2152 m_nFontEncoding = enc;
2153 m_nFontStyle = style;
2154 }
2155
2156
ChangeFontSize(unsigned short s)2157 void ChatManager::ChangeFontSize(unsigned short s)
2158 {
2159 //CPChat_ChangeFontSize p(s);
2160 //SendPacket(&p);
2161
2162 CBuffer buf(4);
2163 buf.PackUnsignedLong(s);
2164 SendBuffer(&buf, CHAT_FONTxSIZE);
2165
2166 m_nFontSize = s;
2167 }
2168
2169
ChangeFontFace(bool b,bool i,bool u,bool s)2170 void ChatManager::ChangeFontFace(bool b, bool i, bool u, bool s)
2171 {
2172 //CPChat_ChangeFontFace p(b, i, u);
2173 //SendPacket(&p);
2174
2175 m_nFontFace = FONT_PLAIN;
2176 if (b) m_nFontFace |= FONT_BOLD;
2177 if (i) m_nFontFace |= FONT_ITALIC;
2178 if (u) m_nFontFace |= FONT_UNDERLINE;
2179 if (s) m_nFontFace |= FONT_STRIKEOUT;
2180
2181 CBuffer buf(4);
2182 buf.PackUnsignedLong(m_nFontFace);
2183 SendBuffer(&buf, CHAT_FONTxFACE);
2184 }
2185
2186
ChangeColorFg(int r,int g,int b)2187 void ChatManager::ChangeColorFg(int r, int g, int b)
2188 {
2189 //CPChat_ChangeColorFg p(r, g, b);
2190 //SendPacket(&p);
2191
2192 CBuffer buf(4);
2193 buf.PackChar(r);
2194 buf.PackChar(g);
2195 buf.PackChar(b);
2196 buf.PackChar(0);
2197 SendBuffer(&buf, CHAT_COLORxFG);
2198
2199 m_nColorFore[0] = r;
2200 m_nColorFore[1] = g;
2201 m_nColorFore[2] = b;
2202 }
2203
2204
ChangeColorBg(int r,int g,int b)2205 void ChatManager::ChangeColorBg(int r, int g, int b)
2206 {
2207 //CPChat_ChangeColorBg p(r, g, b);
2208 //SendPacket(&p);
2209
2210 CBuffer buf(4);
2211 buf.PackChar(r);
2212 buf.PackChar(g);
2213 buf.PackChar(b);
2214 buf.PackChar(0);
2215 SendBuffer(&buf, CHAT_COLORxBG);
2216
2217 m_nColorBack[0] = r;
2218 m_nColorBack[1] = g;
2219 m_nColorBack[2] = b;
2220 }
2221
2222
2223 //----ChatManager::CloseChat------------------------------------------------
CloseChat()2224 void ChatManager::CloseChat()
2225 {
2226 // Close the chat thread
2227 // We must do it before trying to close the socket to avoid
2228 // the chat thread trying to close the socket itself once
2229 // it notices it cannot read from it
2230 myThreadPipe.putChar('X');
2231 if (m_bThreadCreated)
2232 pthread_join(thread_chat, NULL);
2233 m_bThreadCreated = false;
2234
2235 ChatUser* u = NULL;
2236 CBuffer buf;
2237 SendBuffer(&buf, CHAT_DISCONNECTION);
2238 while (chatUsers.size() > 0)
2239 {
2240 u = chatUsers.front();
2241 sockman.CloseSocket(u->sock.Descriptor(), false, false);
2242 u->state = CHAT_STATE_DISCONNECTED;
2243 chatUsersClosed.push_back(u);
2244 chatUsers.pop_front();
2245 // Alert the plugin
2246 PushChatEvent(new IcqChatEvent(CHAT_DISCONNECTION, u));
2247 }
2248
2249 sockman.CloseSocket(chatServer.Descriptor(), false, false);
2250 }
2251
2252
2253 //----ChatManager::FinishKickVote-------------------------------------------
FinishKickVote(VoteInfoList::iterator iter,bool bPassed)2254 void ChatManager::FinishKickVote(VoteInfoList::iterator iter, bool bPassed)
2255 {
2256 char voteId[16];
2257 snprintf(voteId, 16, "%lu", (*iter)->nUin);
2258 Licq::UserId userId(myUserId, voteId);
2259
2260 // Find the person we are kicking in the ChatUserList
2261 ChatUserList::iterator userIter;
2262 for (userIter = chatUsers.begin(); userIter != chatUsers.end(); ++userIter)
2263 {
2264 if ((*userIter)->userId() == userId)
2265 break;
2266 }
2267
2268 // User no longer in the chat
2269 if (userIter == chatUsers.end())
2270 {
2271 delete *iter;
2272 voteInfo.erase(iter);
2273 return;
2274 }
2275
2276 // Send a CHAT_KICKxPASS or CHAT_KICKxFAIL to everyone but the person
2277 // that is attempting to be kicked.
2278 CBuffer buf(6);
2279 buf.PackUnsignedLong((*iter)->nUin);
2280 buf.PackChar((*iter)->nYes);
2281 buf.PackChar((*iter)->nNo);
2282
2283 if (bPassed)
2284 SendBuffer(&buf, CHAT_KICKxPASS, voteId, true);
2285 else
2286 SendBuffer(&buf, CHAT_KICKxFAIL, voteId, true);
2287
2288 // Send the person a notice if they were kicked
2289 if (bPassed)
2290 {
2291 SendBuffer(&buf, CHAT_KICKxYOU, voteId, false);
2292 CloseClient(*userIter);
2293 }
2294
2295 delete *iter;
2296 voteInfo.erase(iter);
2297 }
2298
2299
2300 //----ChatManager::CloseClient----------------------------------------------
CloseClient(ChatUser * u)2301 void ChatManager::CloseClient(ChatUser* u)
2302 {
2303 // Remove the user from the user list
2304 ChatUserList::iterator iter;
2305 for (iter = chatUsers.begin(); iter != chatUsers.end(); ++iter)
2306 {
2307 if (u == *iter)
2308 {
2309 sockman.CloseSocket(u->sock.Descriptor(), false, false);
2310 chatUsers.erase(iter);
2311 u->state = CHAT_STATE_DISCONNECTED;
2312 chatUsersClosed.push_back(u);
2313 break;
2314 }
2315 }
2316
2317 // Alert the plugin
2318 PushChatEvent(new IcqChatEvent(CHAT_DISCONNECTION, u));
2319 }
2320
2321
2322 //-----ChatManager::ClientsStr----------------------------------------------
clientsString() const2323 string ChatManager::clientsString() const
2324 {
2325 string sz;
2326
2327 ChatUserList::const_iterator iter;
2328 for (iter = chatUsers.begin(); iter != chatUsers.end(); ++iter)
2329 {
2330 if (!sz.empty())
2331 sz += ", ";
2332 if ((*iter)->name().empty())
2333 sz += (*iter)->userId().accountId();
2334 else
2335 sz += (*iter)->name();
2336 }
2337 return sz;
2338 }
2339
getEncoding(int chatEncoding)2340 string ChatManager::getEncoding(int chatEncoding)
2341 {
2342 switch (chatEncoding) {
2343 case Licq::ENCODING_ANSI: return "CP 1252";
2344 case Licq::ENCODING_SHIFTJIS: return "Shift-JIS";
2345 case Licq::ENCODING_GB2312: return "GBK";
2346 case Licq::ENCODING_CHINESEBIG5: return "Big5";
2347 case Licq::ENCODING_GREEK: return "CP 1253";
2348 case Licq::ENCODING_TURKISH: return "CP 1254";
2349 case Licq::ENCODING_HEBREW: return "CP 1255";
2350 case Licq::ENCODING_ARABIC: return "CP 1256";
2351 case Licq::ENCODING_BALTIC: return "CP 1257";
2352 case Licq::ENCODING_RUSSIAN: return "CP 1251";
2353 case Licq::ENCODING_THAI: return "TIS-620";
2354 case Licq::ENCODING_EASTEUROPE: return "CP 1250";
2355 default: return "UTF-8";
2356 }
2357 }
2358
userEncoding(const ChatUser * u)2359 string ChatManager::userEncoding(const ChatUser* u)
2360 {
2361 return getEncoding(u->fontEncoding);
2362 }
2363
ChatManager_tep(void * arg)2364 void* LicqIcq::ChatManager_tep(void* arg)
2365 {
2366 ChatManager *chatman = (ChatManager *)arg;
2367
2368 fd_set f;
2369 int l, nSocketsAvailable, nCurrentSocket;
2370
2371 if (chatman->m_pChatClient)
2372 {
2373 if (!chatman->ConnectToChat(chatman->m_pChatClient))
2374 {
2375 chatman->PushChatEvent(new IcqChatEvent(CHAT_ERRORxCONNECT, NULL));
2376 return NULL;
2377 }
2378 chatman->m_pChatClient = 0;
2379 }
2380
2381 while (true)
2382 {
2383 f = chatman->sockman.socketSet();
2384 l = chatman->sockman.LargestSocket() + 1;
2385
2386 // Add the new socket pipe descriptor
2387 FD_SET(chatman->myThreadPipe.getReadFd(), &f);
2388 if (chatman->myThreadPipe.getReadFd() >= l)
2389 l = chatman->myThreadPipe.getReadFd() + 1;
2390
2391 nSocketsAvailable = select(l, &f, NULL, NULL, NULL);
2392
2393 nCurrentSocket = 0;
2394 while (nSocketsAvailable > 0 && nCurrentSocket < l)
2395 {
2396 if (FD_ISSET(nCurrentSocket, &f))
2397 {
2398 // New socket event ----------------------------------------------------
2399 if (nCurrentSocket == chatman->myThreadPipe.getReadFd())
2400 {
2401 char buf = chatman->myThreadPipe.getChar();
2402 if (buf == 'R')
2403 {
2404 DEBUG_THREADS("[ChatManager_tep] Reloading socket info.\n");
2405 }
2406 else if (buf == 'X')
2407 {
2408 DEBUG_THREADS("[ChatManager_tep] Exiting.\n");
2409 pthread_exit(NULL);
2410 }
2411 }
2412
2413 // Connection on the server port ---------------------------------------
2414 else if (nCurrentSocket == chatman->chatServer.Descriptor())
2415 {
2416 if (chatman->sockman.Num() >= MAX_CONNECTS)
2417 {
2418 // Too many sockets, drop this one
2419 gLog.warning(tr("Too many connected clients, rejecting new connection."));
2420 }
2421 else
2422 {
2423 ChatUser* u = new ChatUser;
2424 u->m_pClient = new ChatClient;
2425
2426 if (chatman->chatServer.RecvConnection(u->sock))
2427 {
2428 chatman->sockman.AddSocket(&u->sock);
2429 chatman->sockman.DropSocket(&u->sock);
2430
2431 u->state = CHAT_STATE_HANDSHAKE;
2432 chatman->chatUsers.push_back(u);
2433 gLog.info(tr("Chat: Received connection."));
2434 }
2435 else
2436 {
2437 delete u;
2438 gLog.error(tr("Chat: Unable to receive new connection."));
2439 }
2440 }
2441 }
2442
2443 // Message from connected socket----------------------------------------
2444 else
2445 {
2446 ChatUser* u = chatman->FindChatUser(nCurrentSocket);
2447 if (u == NULL)
2448 {
2449 gLog.warning(tr("Chat: No user owns socket %d."), nCurrentSocket);
2450 }
2451 else
2452 {
2453 pthread_mutex_lock(&u->mutex);
2454 u->sock.Lock();
2455 bool ok = true;
2456
2457 if (u->state != CHAT_STATE_CONNECTED)
2458 {
2459 ok = chatman->ProcessPacket(u);
2460 }
2461
2462 else // Raw character being received
2463 {
2464 ok = chatman->ProcessRaw(u);
2465 }
2466
2467 u->sock.Unlock();
2468 if (!ok) chatman->CloseClient(u);
2469 pthread_mutex_unlock(&u->mutex);
2470 }
2471 }
2472
2473 nSocketsAvailable--;
2474 }
2475 nCurrentSocket++;
2476 }
2477 }
2478 return NULL;
2479 }
2480
ChatWaitForSignal_tep(void * arg)2481 void* LicqIcq::ChatWaitForSignal_tep(void* arg)
2482 {
2483 pthread_detach(pthread_self());
2484
2485 struct SChatReverseConnectInfo *rc = (struct SChatReverseConnectInfo *)arg;
2486 pthread_mutex_t *cancel_mutex = &ChatManager::waiting_thread_cancel_mutex;
2487
2488 pthread_mutex_lock(cancel_mutex);
2489 pthread_cleanup_push(ChatWaitForSignal_cleanup, arg);
2490 pthread_testcancel();
2491 pthread_cleanup_pop(0);
2492 pthread_mutex_unlock(cancel_mutex);
2493
2494 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
2495 gLog.info(tr("Chat: Waiting for reverse connection."));
2496 bool bConnected = gIcqProtocol.waitForReverseConnection(rc->nId, rc->u->userId());
2497 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
2498
2499 pthread_mutex_lock(cancel_mutex);
2500 pthread_cleanup_push(ChatWaitForSignal_cleanup, arg);
2501 pthread_testcancel();
2502 pthread_cleanup_pop(0);
2503
2504 if (bConnected || !rc->bTryDirect)
2505 {
2506 if (!bConnected && rc->m->chatUsers.empty())
2507 rc->m->PushChatEvent(new IcqChatEvent(CHAT_ERRORxCONNECT, NULL));
2508
2509
2510 pthread_mutex_lock(&rc->m->thread_list_mutex);
2511 ThreadList::iterator iter;
2512 for (iter = rc->m->waitingThreads.begin();
2513 iter != rc->m->waitingThreads.end(); ++iter)
2514 {
2515 if (pthread_equal(*iter, pthread_self()))
2516 {
2517 rc->m->waitingThreads.erase(iter);
2518 break;
2519 }
2520 }
2521 pthread_mutex_unlock(&rc->m->thread_list_mutex);
2522 pthread_mutex_unlock(cancel_mutex);
2523
2524 delete rc->u->m_pClient;
2525 delete rc->u;
2526 delete rc;
2527 pthread_exit(NULL);
2528 }
2529
2530 pthread_mutex_unlock(cancel_mutex);
2531
2532 bool bSendIntIp = false;
2533 {
2534 Licq::UserReadGuard temp_user(rc->u->userId());
2535 if (temp_user.isLocked())
2536 bSendIntIp = temp_user->SendIntIp();
2537 }
2538
2539 pthread_mutex_lock(cancel_mutex);
2540 pthread_cleanup_push(ChatWaitForSignal_cleanup, arg);
2541 pthread_testcancel();
2542 pthread_cleanup_pop(0);
2543
2544 unsigned long nIp = rc->u->m_pClient->m_nIp;
2545 unsigned long nIntIp = rc->u->m_pClient->m_nIntIp;
2546 unsigned short nPort = rc->u->m_pClient->m_nPort;
2547 pthread_mutex_unlock(cancel_mutex);
2548
2549 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
2550 gLog.info(tr("Chat: Reverse connection failed, trying direct."));
2551 bool bSuccess = gIcqProtocol.OpenConnectionToUser("chat", nIp, nIntIp, &rc->u->sock,
2552 nPort, bSendIntIp);
2553 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
2554 if (bSuccess)
2555 {
2556 pthread_mutex_lock(cancel_mutex);
2557 pthread_cleanup_push(ChatWaitForSignal_cleanup, arg);
2558 pthread_testcancel();
2559 pthread_cleanup_pop(0);
2560
2561 if (rc->m->SendChatHandshake(rc->u))
2562 {
2563 rc->m->chatUsers.push_back(rc->u);
2564
2565 pthread_mutex_lock(&rc->m->thread_list_mutex);
2566 ThreadList::iterator iter;
2567 for (iter = rc->m->waitingThreads.begin();
2568 iter != rc->m->waitingThreads.end(); ++iter)
2569 {
2570 if (pthread_equal(*iter, pthread_self()))
2571 {
2572 rc->m->waitingThreads.erase(iter);
2573 break;
2574 }
2575 }
2576 pthread_mutex_unlock(&rc->m->thread_list_mutex);
2577 pthread_mutex_unlock(cancel_mutex);
2578
2579 delete rc;
2580 pthread_exit(NULL);
2581 }
2582
2583 pthread_mutex_unlock(cancel_mutex);
2584 }
2585
2586 pthread_mutex_lock(cancel_mutex);
2587 pthread_cleanup_push(ChatWaitForSignal_cleanup, arg);
2588 pthread_testcancel();
2589 pthread_cleanup_pop(0);
2590
2591 if (rc->m->chatUsers.empty())
2592 rc->m->PushChatEvent(new IcqChatEvent(CHAT_ERRORxCONNECT, NULL));
2593
2594 pthread_mutex_lock(&rc->m->thread_list_mutex);
2595 ThreadList::iterator iter2;
2596 for (iter2 = rc->m->waitingThreads.begin();
2597 iter2 != rc->m->waitingThreads.end(); ++iter2)
2598 {
2599 if (pthread_equal(*iter2, pthread_self()))
2600 {
2601 rc->m->waitingThreads.erase(iter2);
2602 break;
2603 }
2604 }
2605 pthread_mutex_unlock(&rc->m->thread_list_mutex);
2606 pthread_mutex_unlock(cancel_mutex);
2607
2608
2609 delete rc->u->m_pClient;
2610 delete rc->u;
2611 delete rc;
2612
2613 pthread_exit(NULL);
2614 }
2615
ChatWaitForSignal_cleanup(void * arg)2616 void LicqIcq::ChatWaitForSignal_cleanup(void* arg)
2617 {
2618 struct SChatReverseConnectInfo *rc = (struct SChatReverseConnectInfo *)arg;
2619
2620 delete rc->u->m_pClient;
2621 delete rc->u;
2622 delete rc;
2623 pthread_mutex_unlock(&ChatManager::waiting_thread_cancel_mutex);
2624 }
2625
FindByPort(unsigned short p)2626 ChatManager *ChatManager::FindByPort(unsigned short p)
2627 {
2628 pthread_mutex_lock(&cmList_mutex);
2629 ChatManagerList::iterator iter;
2630 ChatManager *cm = NULL;
2631 for (iter = cmList.begin(); iter != cmList.end(); ++iter)
2632 {
2633 if ( (*iter)->LocalPort() == p)
2634 {
2635 cm = *iter;
2636 break;
2637 }
2638 }
2639 pthread_mutex_unlock(&cmList_mutex);
2640 return cm;
2641 }
2642
2643
~ChatManager()2644 ChatManager::~ChatManager()
2645 {
2646 // cancel all waiting threads first
2647 pthread_mutex_lock(&waiting_thread_cancel_mutex);
2648 pthread_mutex_lock(&thread_list_mutex);
2649 ThreadList::iterator t_iter;
2650 for (t_iter = waitingThreads.begin(); t_iter != waitingThreads.end();)
2651 {
2652 pthread_cancel(*t_iter);
2653 t_iter = waitingThreads.erase(t_iter);
2654 }
2655 pthread_mutex_unlock(&thread_list_mutex);
2656 pthread_mutex_unlock(&waiting_thread_cancel_mutex);
2657
2658 CloseChat();
2659
2660 // Delete all the users
2661 ChatUser* u = NULL;
2662 while (chatUsersClosed.size() > 0)
2663 {
2664 u = chatUsersClosed.front();
2665 if (u->m_pClient)
2666 delete u->m_pClient;
2667 delete u;
2668 chatUsersClosed.pop_front();
2669 }
2670
2671 // Delete any pending events
2672 IcqChatEvent *e = NULL;
2673 while (chatEvents.size() > 0)
2674 {
2675 e = chatEvents.front();
2676 delete e;
2677 chatEvents.pop_front();
2678 }
2679
2680 pthread_mutex_lock(&cmList_mutex);
2681 ChatManagerList::iterator iter;
2682 for (iter = cmList.begin(); iter != cmList.end(); ++iter)
2683 {
2684 if (*iter == this) break;
2685 }
2686 if (iter != cmList.end()) cmList.erase(iter);
2687 pthread_mutex_unlock(&cmList_mutex);
2688 }
2689
2690