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