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 "icq.h"
21 
22 #include <ctime>
23 #include <sstream>
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <cerrno>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <langinfo.h>
33 
34 #include <licq/byteorder.h>
35 #include <licq/contactlist/usermanager.h>
36 #include <licq/daemon.h>
37 #include <licq/event.h>
38 #include <licq/gpghelper.h>
39 #include <licq/icq/chat.h>
40 #include <licq/oneventmanager.h>
41 #include <licq/plugin/pluginmanager.h>
42 #include <licq/pluginsignal.h>
43 #include <licq/protocolmanager.h>
44 #include <licq/protocolsignal.h>
45 #include <licq/statistics.h>
46 #include <licq/translator.h>
47 #include <licq/userevents.h>
48 #include <licq/logging/log.h>
49 #include <licq/version.h>
50 
51 #include "filetransfer.h"
52 #include "gettext.h"
53 #include "oscarservice.h"
54 #include "owner.h"
55 #include "packet-srv.h"
56 #include "packet-tcp.h"
57 #include "protocolsignal.h"
58 #include "socket.h"
59 #include "user.h"
60 
61 using namespace LicqIcq;
62 using Licq::Daemon;
63 using Licq::IcqPluginActive;
64 using Licq::IcqPluginBusy;
65 using Licq::IcqPluginInactive;
66 using Licq::Log;
67 using Licq::OnEventData;
68 using Licq::StringList;
69 using Licq::gDaemon;
70 using Licq::gLog;
71 using Licq::gOnEventManager;
72 using Licq::gTranslator;
73 using std::list;
74 using std::string;
75 
icqSendMessage(const Licq::ProtoSendMessageSignal * ps)76 void IcqProtocol::icqSendMessage(const Licq::ProtoSendMessageSignal* ps)
77 {
78   const Licq::UserId& userId(ps->userId());
79   unsigned flags(ps->flags());
80   const Licq::Color* pColor(ps->color());
81   const string accountId = userId.accountId();
82   string m = gTranslator.returnToDos(ps->message());
83 
84   bool bUserOffline = true;
85   Licq::EventMsg* e = NULL;
86 
87   unsigned long f = Licq::EventMsg::FlagLicqVerMask | Licq::EventMsg::FlagSender;
88   bool useGpg = false;
89   {
90     Licq::UserReadGuard u(userId);
91     if (u.isLocked())
92     {
93       bUserOffline = !u->isOnline();
94       if (!bUserOffline)
95         useGpg = u->UseGPG();
96     }
97   }
98   if (useGpg)
99   {
100     char* cipher = Licq::gGpgHelper.Encrypt(m.c_str(), userId);
101     if (cipher != NULL)
102     {
103       m = cipher;
104       free(cipher);
105       f |= Licq::UserEvent::FlagEncrypted;
106     }
107     else
108       useGpg = false;
109   }
110 
111   unsigned short nLevel = ICQ_TCPxMSG_NORMAL;
112   if (flags & Licq::ProtocolSignal::SendUrgent)
113   {
114     f |= Licq::UserEvent::FlagUrgent;
115     nLevel = ICQ_TCPxMSG_URGENT;
116   }
117   else if (flags & Licq::ProtocolSignal::SendToList)
118     nLevel = ICQ_TCPxMSG_LIST;
119   if (flags & Licq::ProtocolSignal::SendToMultiple)
120     f |= Licq::UserEvent::FlagMultiRec;
121 
122   if ((flags & Licq::ProtocolSignal::SendDirect) == 0)
123   {
124     unsigned short nCharset = CHARSET_ASCII;
125 
126     if (!useGpg && !gTranslator.isAscii(m))
127     {
128       nCharset = CHARSET_UNICODE;
129       m = gTranslator.fromUtf8(m, "UCS-2BE");
130     }
131 
132     e = new Licq::EventMsg(ps->message(), Licq::EventMsg::TimeNow, f);
133     unsigned short nMaxSize = bUserOffline ? Licq::IcqProtocol::MaxOfflineMessageSize : Licq::IcqProtocol::MaxMessageSize;
134     if (m.size() > nMaxSize)
135     {
136       gLog.warning(tr("Truncating message to %d characters to send through server."), nMaxSize);
137       m.resize(nMaxSize);
138     }
139     icqSendThroughServer(ps->callerThread(), ps->eventId(), userId,
140         ICQ_CMDxSUB_MSG | ((flags & Licq::ProtocolSignal::SendToMultiple) ? ICQ_CMDxSUB_FxMULTIREC : 0),
141         m, e, nCharset);
142   }
143 
144   UserWriteGuard u(userId);
145 
146   if (flags & Licq::ProtocolSignal::SendDirect)
147   {
148     f |= Licq::UserEvent::FlagDirect;
149 
150     if (!u.isLocked())
151       return;
152     if (u->Secure())
153       f |= Licq::UserEvent::FlagEncrypted;
154     e = new Licq::EventMsg(ps->message(), Licq::EventMsg::TimeNow, f);
155     if (pColor != NULL) e->SetColor(pColor);
156     CPT_Message* p = new CPT_Message(m, nLevel, flags & Licq::ProtocolSignal::SendToMultiple,
157         pColor, *u, !gTranslator.isAscii(m));
158     gLog.info(tr("Sending %smessage to %s (#%d)."),
159         (flags & Licq::ProtocolSignal::SendUrgent) ? tr("urgent ") : "",
160         u->getAlias().c_str(), -p->Sequence());
161     SendExpectEvent_Client(ps, *u, p, e);
162   }
163 
164   if (u.isLocked())
165   {
166     u->SetSendServer((flags & Licq::ProtocolSignal::SendDirect) == 0);
167     u->SetSendLevel(nLevel);
168   }
169 
170   if (pColor != NULL)
171     Licq::Color::setDefaultColors(pColor);
172 }
173 
icqFetchAutoResponse(const Licq::ProtocolSignal * ps)174 void IcqProtocol::icqFetchAutoResponse(const Licq::ProtocolSignal* ps)
175 {
176   const Licq::UserId& userId(ps->userId());
177   if (userId.isOwner())
178     return;
179 
180   if (isalpha(userId.accountId()[0]))
181   {
182     icqFetchAutoResponseServer(ps);
183     return;
184   }
185 
186   UserWriteGuard u(userId);
187 
188   if (u->normalSocketDesc() <= 0 && u->Version() > 6)
189   {
190     // Generic read, gets changed in constructor
191     CSrvPacketTcp *s = new CPU_AdvancedMessage(*u, ICQ_CMDxTCP_READxAWAYxMSG, 0, false, 0, 0, 0);
192     gLog.info(tr("Requesting auto response from %s."), u->getAlias().c_str());
193     SendExpectEvent_Server(ps, userId, s, NULL);
194   }
195   else
196   {
197     CPT_ReadAwayMessage *p = new CPT_ReadAwayMessage(*u);
198     gLog.info(tr("Requesting auto response from %s (#%d)."),
199         u->getAlias().c_str(), -p->Sequence());
200     SendExpectEvent_Client(ps, *u, p, NULL);
201   }
202 }
203 
icqSendUrl(const Licq::ProtoSendUrlSignal * ps)204 void IcqProtocol::icqSendUrl(const Licq::ProtoSendUrlSignal* ps)
205 {
206   if (ps->userId().isOwner())
207     return;
208 
209   string userEncoding = getUserEncoding(ps->userId());
210   const Licq::UserId& userId(ps->userId());
211   unsigned flags(ps->flags());
212   const Licq::Color* pColor(ps->color());
213   const string accountId = userId.accountId();
214 
215   // make the URL info string
216   string m = gTranslator.fromUtf8(gTranslator.returnToDos(ps->message()), userEncoding);
217   int n = ps->url().size() + m.size() + 2;
218   if ((flags & Licq::ProtocolSignal::SendDirect) == 0 && n > Licq::IcqProtocol::MaxMessageSize)
219     m.erase(Licq::IcqProtocol::MaxMessageSize - ps->url().size() - 2);
220   m += '\xFE';
221   m += gTranslator.fromUtf8(ps->url(), userEncoding);
222 
223   unsigned long f = Licq::EventUrl::FlagLicqVerMask | Licq::EventUrl::FlagSender;
224   unsigned short nLevel = ICQ_TCPxMSG_NORMAL;
225   if (flags & Licq::ProtocolSignal::SendDirect)
226     f |= Licq::UserEvent::FlagDirect;
227   if (flags & Licq::ProtocolSignal::SendUrgent)
228   {
229     f |= Licq::UserEvent::FlagUrgent;
230     nLevel = ICQ_TCPxMSG_URGENT;
231   }
232   else if (flags & Licq::ProtocolSignal::SendToList)
233   {
234     nLevel = ICQ_TCPxMSG_LIST;
235   }
236   if (flags & Licq::ProtocolSignal::SendToMultiple)
237     f |= Licq::UserEvent::FlagMultiRec;
238 
239   if ((flags & Licq::ProtocolSignal::SendDirect) == 0)
240   {
241     unsigned short nCharset = 0;
242     {
243       Licq::UserReadGuard u(userId);
244       if (u.isLocked() && !u->userEncoding().empty())
245         nCharset = 3;
246     }
247 
248     Licq::EventUrl* e = new Licq::EventUrl(ps->url(), ps->message(), Licq::EventUrl::TimeNow, f);
249     icqSendThroughServer(ps->callerThread(), ps->eventId(), userId,
250         ICQ_CMDxSUB_URL | ((flags & Licq::ProtocolSignal::SendToMultiple) ? ICQ_CMDxSUB_FxMULTIREC : 0), m, e, nCharset);
251   }
252 
253   UserWriteGuard u(userId);
254 
255   if (flags & Licq::ProtocolSignal::SendDirect)
256   {
257     if (!u.isLocked())
258       return;
259     if (u->Secure())
260       f |= Licq::UserEvent::FlagEncrypted;
261     Licq::EventUrl* e = new Licq::EventUrl(ps->url(), ps->message(), Licq::EventUrl::TimeNow, f);
262     if (pColor != NULL) e->SetColor(pColor);
263     CPT_Url* p = new CPT_Url(m, nLevel, flags & Licq::ProtocolSignal::SendToMultiple, pColor, *u);
264     gLog.info(tr("Sending %sURL to %s (#%d)."),
265         (flags & Licq::ProtocolSignal::SendUrgent) ? tr("urgent ") : "",
266         u->getAlias().c_str(), -p->Sequence());
267     SendExpectEvent_Client(ps, *u, p, e);
268   }
269   if (u.isLocked())
270   {
271     u->SetSendServer((flags & Licq::ProtocolSignal::SendDirect) == 0);
272     u->SetSendLevel(nLevel);
273   }
274 
275   if (pColor != NULL)
276     Licq::Color::setDefaultColors(pColor);
277 }
278 
icqFileTransfer(const Licq::ProtoSendFileSignal * ps)279 void IcqProtocol::icqFileTransfer(const Licq::ProtoSendFileSignal* ps)
280 {
281   const Licq::UserId& userId(ps->userId());
282   unsigned flags(ps->flags());
283 
284   if (userId.isOwner())
285     return;
286 
287   UserWriteGuard u(userId);
288   if (!u.isLocked())
289     return;
290 
291   string dosDesc = gTranslator.fromUtf8(gTranslator.returnToDos(ps->message()), u->userEncoding());
292 
293   unsigned short nLevel;
294 
295   if ((flags & Licq::ProtocolSignal::SendDirect) == 0)
296   {
297     unsigned long f = LICQ_VERSION | Licq::EventFile::FlagSender;
298     //flags through server are a little different
299     if (flags & Licq::ProtocolSignal::SendUrgent)
300     {
301       f |= Licq::UserEvent::FlagUrgent;
302       nLevel = ICQ_TCPxMSG_URGENT2;
303     }
304     else if (flags & Licq::ProtocolSignal::SendToList)
305       nLevel = ICQ_TCPxMSG_LIST2;
306     else
307       nLevel = ICQ_TCPxMSG_NORMAL2;
308 
309     CPU_FileTransfer* p = new CPU_FileTransfer(*u, ps->files(), ps->filename(),
310         dosDesc, nLevel, (u->Version() > 7));
311 
312     if (!p->IsValid())
313     {
314       delete p;
315     }
316     else
317     {
318       Licq::EventFile* e = new Licq::EventFile(ps->filename(), ps->message(), p->GetFileSize(),
319           ps->files(), p->Sequence(), Licq::EventFile::TimeNow, f);
320       gLog.info(tr("Sending file transfer to %s (#%d)."),
321           u->getAlias().c_str(), -p->Sequence());
322 
323       SendExpectEvent_Server(userId, p, e);
324     }
325   }
326   else
327   {
328     unsigned long f = Licq::EventFile::FlagLicqVerMask | Licq::EventFile::FlagDirect | Licq::EventFile::FlagSender;
329 
330     if (flags & Licq::ProtocolSignal::SendUrgent)
331     {
332       f |= Licq::UserEvent::FlagUrgent;
333       nLevel = ICQ_TCPxMSG_URGENT;
334     }
335     else if (flags & Licq::ProtocolSignal::SendToList)
336       nLevel = ICQ_TCPxMSG_LIST;
337     else
338       nLevel = ICQ_TCPxMSG_NORMAL;
339     if (u->Secure())
340       f |= Licq::UserEvent::FlagEncrypted;
341 
342     CPT_FileTransfer* p = new CPT_FileTransfer(ps->files(), ps->filename(), dosDesc, nLevel, *u);
343 
344     if (!p->IsValid())
345     {
346       delete p;
347     }
348     else
349     {
350       Licq::EventFile* e = new Licq::EventFile(ps->filename(), ps->message(), p->GetFileSize(),
351           ps->files(), p->Sequence(), Licq::EventFile::TimeNow, f);
352       gLog.info(tr("Sending %sfile transfer to %s (#%d)."),
353           (flags & Licq::ProtocolSignal::SendUrgent) ? tr("urgent ") : "",
354           u->getAlias().c_str(), -p->Sequence());
355 
356       SendExpectEvent_Client(ps, *u, p, e);
357     }
358   }
359 
360   u->SetSendServer((flags & Licq::ProtocolSignal::SendDirect) == 0);
361   u->SetSendLevel(nLevel);
362 }
363 
364 //-----CICQDaemon::sendContactList-------------------------------------------
icqSendContactList(const ProtoSendContactsSignal * ps)365 void IcqProtocol::icqSendContactList(const ProtoSendContactsSignal* ps)
366 {
367   const Licq::UserId& userId(ps->userId());
368   const StringList& users(ps->users());
369   unsigned flags = ps->flags();
370   const Licq::Color* pColor(ps->color());
371 
372   if (userId.isOwner())
373     return;
374 
375   string userEncoding = getUserEncoding(userId);
376 
377   std::stringstream buf;
378   buf << users.size() << '\xFE';
379   Licq::EventContactList::ContactList vc;
380 
381   StringList::const_iterator iter;
382   for (iter = users.begin(); iter != users.end(); ++iter)
383   {
384     Licq::UserId uId(myOwnerId, *iter);
385     Licq::UserReadGuard u(uId);
386     string alias = (u.isLocked() ? u->getAlias() : "");
387     buf << *iter << '\xFE';
388     buf << gTranslator.fromUtf8(alias, userEncoding) << '\xFE';
389     vc.push_back(new Licq::EventContactList::Contact(uId, alias));
390   }
391   string m = buf.str();
392 
393   if ((flags & Licq::ProtocolSignal::SendDirect) == 0 && (int)m.size() > Licq::IcqProtocol::MaxMessageSize)
394   {
395     gLog.warning(tr("Contact list too large to send through server."));
396     return;
397   }
398 
399   unsigned long f = Licq::EventContactList::FlagLicqVerMask | Licq::EventContactList::FlagSender;
400   unsigned short nLevel = ICQ_TCPxMSG_NORMAL;
401   if (flags & Licq::ProtocolSignal::SendDirect)
402     f |= Licq::UserEvent::FlagDirect;
403   if (flags & Licq::ProtocolSignal::SendUrgent)
404   {
405     f |= Licq::UserEvent::FlagUrgent;
406     nLevel = ICQ_TCPxMSG_URGENT;
407   }
408   else if (flags & Licq::ProtocolSignal::SendToList)
409     nLevel = ICQ_TCPxMSG_LIST;
410   if (flags & Licq::ProtocolSignal::SendToMultiple)
411     f |= Licq::UserEvent::FlagMultiRec;
412 
413   if ((flags & Licq::ProtocolSignal::SendDirect) == 0) // send offline
414   {
415     Licq::EventContactList* e = new Licq::EventContactList(vc, false, Licq::EventContactList::TimeNow, f);
416     icqSendThroughServer(ps->callerThread(), ps->eventId(), userId,
417       ICQ_CMDxSUB_CONTACTxLIST | ((flags & Licq::ProtocolSignal::SendToMultiple) ? ICQ_CMDxSUB_FxMULTIREC : 0),
418       m, e);
419   }
420 
421   UserWriteGuard u(userId);
422   if (flags & Licq::ProtocolSignal::SendDirect)
423   {
424     if (!u.isLocked())
425       return;
426     if (u->Secure())
427       f |= Licq::UserEvent::FlagEncrypted;
428     Licq::EventContactList* e = new Licq::EventContactList(vc, false, Licq::EventContactList::TimeNow, f);
429     if (pColor != NULL) e->SetColor(pColor);
430     CPT_ContactList *p = new CPT_ContactList(m, nLevel, flags & Licq::ProtocolSignal::SendToMultiple, pColor, *u);
431     gLog.info(tr("Sending %scontact list to %s (#%d)."),
432         (flags & Licq::ProtocolSignal::SendUrgent) ? tr("urgent ") : "",
433         u->getAlias().c_str(), -p->Sequence());
434     SendExpectEvent_Client(ps, *u, p, e);
435   }
436   if (u.isLocked())
437   {
438     u->SetSendServer((flags & Licq::ProtocolSignal::SendDirect) == 0);
439     u->SetSendLevel(nLevel);
440   }
441 
442   if (pColor != NULL)
443     Licq::Color::setDefaultColors(pColor);
444 }
445 
icqRequestPluginInfo(const Licq::UserId & userId,Licq::IcqProtocol::PluginType type,bool bServer,const Licq::ProtocolSignal * ps)446 void IcqProtocol::icqRequestPluginInfo(const Licq::UserId& userId, Licq::IcqProtocol::PluginType type,
447     bool bServer, const Licq::ProtocolSignal* ps)
448 {
449   if (userId.isOwner())
450     return;
451 
452   UserWriteGuard u(userId);
453   if (!u.isLocked())
454     return;
455 
456   switch (type)
457   {
458     case Licq::IcqProtocol::PluginInfoList:
459       gLog.info(tr("Requesting info plugin list from %s%s."),
460           u->getAlias().c_str(), bServer ? " through server" : "");
461       icqRequestInfoPlugin(*u, bServer, PLUGIN_QUERYxINFO, ps);
462 
463     case Licq::IcqProtocol::PluginPhoneBook:
464       bServer = (u->infoSocketDesc() < 0);
465       gLog.info(tr("Requesting Phone Book from %s%s."),
466           u->getAlias().c_str(), bServer ? " through server" : "");
467       icqRequestInfoPlugin(*u, bServer, PLUGIN_PHONExBOOK, ps);
468 
469     case Licq::IcqProtocol::PluginPicture:
470       bServer = (u->infoSocketDesc() < 0);
471       gLog.info(tr("Requesting Picture from %s%s."),
472           u->getAlias().c_str(), bServer ? " through server" : "");
473       icqRequestInfoPlugin(*u, bServer, PLUGIN_PICTURE, ps);
474 
475     case Licq::IcqProtocol::PluginStatusList:
476       gLog.info(tr("Requesting status plugin list from %s%s."),
477           u->getAlias().c_str(), bServer ? " through server" : "");
478       icqRequestStatusPlugin(*u, bServer, PLUGIN_QUERYxSTATUS, ps);
479 
480     case Licq::IcqProtocol::PluginSharedFiles:
481       gLog.info(tr("Requesting file server status from %s%s."),
482           u->getAlias().c_str(), bServer ? " through server" : "");
483       icqRequestStatusPlugin(*u, bServer, PLUGIN_FILExSERVER, ps);
484 
485     case Licq::IcqProtocol::PluginPhoneFollowMe:
486       gLog.info(tr("Requesting Phone \"Follow Me\" status from %s%s."),
487           u->getAlias().c_str(), bServer ? " through server" : "");
488       icqRequestStatusPlugin(*u, bServer, PLUGIN_FOLLOWxME, ps);
489 
490     case Licq::IcqProtocol::PluginIcqPhone:
491       gLog.info(tr("Requesting ICQphone status from %s%s."),
492           u->getAlias().c_str(), bServer ? " through server" : "");
493       icqRequestStatusPlugin(*u, bServer, PLUGIN_FILExSERVER, ps);
494   };
495 }
496 
497 //-----CICQDaemon::sendInfoPluginReq--------------------------------------------
icqRequestInfoPlugin(User * u,bool bServer,const uint8_t * GUID,const Licq::ProtocolSignal * ps)498 void IcqProtocol::icqRequestInfoPlugin(User* u, bool bServer,
499     const uint8_t* GUID, const Licq::ProtocolSignal* ps)
500 {
501   if (bServer)
502   {
503     CPU_InfoPluginReq *p = new CPU_InfoPluginReq(u, GUID, 0);
504     SendExpectEvent_Server(ps, u->id(), p, NULL);
505   }
506   else
507   {
508     CPT_InfoPluginReq *p = new CPT_InfoPluginReq(u, GUID, 0);
509     SendExpectEvent_Client(ps, u, p, NULL);
510   }
511 }
512 
513 //-----CICQDaemon::sendPictureReq-----------------------------------------------
icqRequestPicture(const Licq::ProtocolSignal * ps)514 void IcqProtocol::icqRequestPicture(const Licq::ProtocolSignal* ps)
515 {
516   bool useBart;
517   {
518     OwnerReadGuard o(myOwnerId);
519     useBart = o->useBart();
520   }
521 
522   size_t iconHashSize;
523   {
524     UserReadGuard user(ps->userId());
525     if (!user.isLocked())
526       return;
527 
528     iconHashSize = user->buddyIconHash().size();
529   }
530 
531   if (useBart && iconHashSize > 0)
532     return m_xBARTService->SendEvent(ps->callerThread(), ps->eventId(), ps->userId(),
533         ICQ_SNACxBART_DOWNLOADxREQUEST, true);
534 
535   icqRequestPluginInfo(ps->userId(), Licq::IcqProtocol::PluginPicture, false, ps);
536 }
537 
538 //-----CICQDaemon::sendStatusPluginReq------------------------------------------
icqRequestStatusPlugin(User * u,bool bServer,const uint8_t * GUID,const Licq::ProtocolSignal * ps)539 void IcqProtocol::icqRequestStatusPlugin(User* u, bool bServer,
540     const uint8_t* GUID, const Licq::ProtocolSignal* ps)
541 {
542   if (bServer)
543   {
544     CPU_StatusPluginReq *p = new CPU_StatusPluginReq(u, GUID, 0);
545     SendExpectEvent_Server(ps, u->id(), p, NULL);
546   }
547   else
548   {
549     CPT_StatusPluginReq *p = new CPT_StatusPluginReq(u, GUID, 0);
550     SendExpectEvent_Client(ps, u, p, NULL);
551   }
552 }
553 
icqFileTransferCancel(const Licq::UserId & userId,unsigned short nSequence)554 void IcqProtocol::icqFileTransferCancel(const Licq::UserId& userId, unsigned short nSequence)
555 {
556   // add to history ??
557   UserWriteGuard u(userId);
558   if (!u.isLocked())
559     return;
560   gLog.info(tr("Cancelling file transfer to %s (#%d)."), u->getAlias().c_str(), -nSequence);
561   CPT_CancelFile p(nSequence, *u);
562   AckTCP(p, u->normalSocketDesc());
563 }
564 
icqFileTransferAccept(const Licq::ProtoSendEventReplySignal * ps)565 void IcqProtocol::icqFileTransferAccept(const Licq::ProtoSendEventReplySignal* ps)
566 {
567    // basically a fancy tcp ack packet which is sent late
568   UserWriteGuard u(ps->userId());
569   if (!u.isLocked())
570     return;
571   gLog.info(tr("Accepting file transfer from %s (#%lu)."), u->getAlias().c_str(), ps->eventId());
572   if (ps->direct())
573   {
574     CPT_AckFileAccept p(ps->port(), ps->eventId(), *u);
575     AckTCP(p, u->normalSocketDesc());
576   }
577   else
578   {
579     unsigned long msgId[2] = { ps->flag1(), ps->flag2() };
580     CPU_AckFileAccept *p = new CPU_AckFileAccept(*u, msgId, ps->eventId(), ps->port(),
581         gTranslator.fromUtf8(gTranslator.returnToDos(ps->message()), u->userEncoding()),
582         ps->filename(), ps->filesize());
583     SendEvent_Server(p);
584   }
585 }
586 
icqFileTransferRefuse(const Licq::ProtoSendEventReplySignal * ps)587 void IcqProtocol::icqFileTransferRefuse(const Licq::ProtoSendEventReplySignal* ps)
588 {
589    // add to history ??
590   UserWriteGuard u(ps->userId());
591   if (!u.isLocked())
592     return;
593   string reasonDos = gTranslator.fromUtf8(gTranslator.returnToDos(ps->message()), u->userEncoding());
594   gLog.info(tr("Refusing file transfer from %s (#%lu)."), u->getAlias().c_str(), ps->eventId());
595 
596   if (ps->direct())
597   {
598     CPT_AckFileRefuse p(reasonDos, ps->eventId(), *u);
599     AckTCP(p, u->normalSocketDesc());
600   }
601   else
602   {
603     unsigned long msgId[2] = { ps->flag1(), ps->flag2() };
604     CPU_AckFileRefuse *p = new CPU_AckFileRefuse(*u, msgId, ps->eventId(), reasonDos);
605     SendEvent_Server(p);
606   }
607 }
608 
icqChatRequest(const ProtoChatRequestSignal * ps)609 void IcqProtocol::icqChatRequest(const ProtoChatRequestSignal* ps)
610 {
611   const Licq::UserId& userId(ps->userId());
612   const string& reason(ps->reason());
613   unsigned flags = ps->flags();
614   const string& chatUsers(ps->chatUsers());
615   unsigned short nPort = ps->port();
616   if (userId.isOwner())
617     return;
618 
619   UserWriteGuard u(userId);
620   if (!u.isLocked())
621     return;
622   string reasonDos = gTranslator.toUtf8(gTranslator.returnToDos(reason), u->userEncoding());
623 
624   unsigned long f;
625   unsigned short nLevel;
626   if ((flags & Licq::ProtocolSignal::SendDirect) == 0)
627   {
628     f = Licq::EventChat::FlagLicqVerMask | Licq::EventChat::FlagSender;
629 
630     //flags through server are a little different
631     if (flags & Licq::ProtocolSignal::SendUrgent)
632     {
633       f |= Licq::UserEvent::FlagUrgent;
634       nLevel = ICQ_TCPxMSG_URGENT2;
635     }
636     else if (flags & Licq::ProtocolSignal::SendToList)
637       nLevel = ICQ_TCPxMSG_LIST2;
638     else
639       nLevel = ICQ_TCPxMSG_NORMAL2;
640 
641     CPU_ChatRequest *p = new CPU_ChatRequest(reasonDos,
642         chatUsers, nPort, nLevel, *u, (u->Version() > 7));
643 
644     Licq::EventChat* e = new Licq::EventChat(reason, chatUsers, nPort, p->Sequence(),
645         Licq::EventChat::TimeNow, f);
646     gLog.info(tr("Sending chat request to %s (#%d)."), u->getAlias().c_str(), -p->Sequence());
647 
648     SendExpectEvent_Server(ps, u->id(), p, e);
649     }
650   else
651   {
652     f = Licq::EventChat::FlagLicqVerMask | Licq::EventChat::FlagDirect | Licq::EventChat::FlagSender;
653     nLevel = ICQ_TCPxMSG_NORMAL;
654     if (flags & Licq::ProtocolSignal::SendUrgent)
655     {
656       f |= Licq::UserEvent::FlagUrgent;
657       nLevel = ICQ_TCPxMSG_URGENT;
658     }
659     else if (flags & Licq::ProtocolSignal::SendToList)
660       nLevel = ICQ_TCPxMSG_LIST;
661     if (u->Secure())
662       f |= Licq::UserEvent::FlagEncrypted;
663 
664     CPT_ChatRequest* p = new CPT_ChatRequest(reasonDos, chatUsers, nPort,
665         nLevel, *u, (u->Version() > 7));
666     Licq::EventChat* e = new Licq::EventChat(reason, chatUsers, nPort, p->Sequence(),
667         Licq::UserEvent::TimeNow, f);
668     gLog.info(tr("Sending %schat request to %s (#%d)."),
669         (flags & Licq::ProtocolSignal::SendUrgent) ? tr("urgent ") : "",
670         u->getAlias().c_str(), -p->Sequence());
671     SendExpectEvent_Client(ps, *u, p, e);
672 	}
673 
674   u->SetSendServer((flags & Licq::ProtocolSignal::SendDirect) == 0);
675   u->SetSendLevel(nLevel);
676 }
677 
icqChatRequestCancel(const Licq::UserId & userId,unsigned short nSequence)678 void IcqProtocol::icqChatRequestCancel(const Licq::UserId& userId, unsigned short nSequence)
679 {
680   UserWriteGuard u(userId);
681   if (!u.isLocked())
682     return;
683   gLog.info(tr("Cancelling chat request with %s (#%d)."), u->getAlias().c_str(), -nSequence);
684   CPT_CancelChat p(nSequence, *u);
685   AckTCP(p, u->normalSocketDesc());
686 }
687 
icqChatRequestRefuse(const ProtoChatRefuseSignal * ps)688 void IcqProtocol::icqChatRequestRefuse(const ProtoChatRefuseSignal* ps)
689 {
690   // add to history ??
691   UserWriteGuard u(ps->userId());
692   if (!u.isLocked())
693     return;
694   gLog.info(tr("Refusing chat request with %s (#%d)."), u->getAlias().c_str(), -ps->sequence());
695   string reasonDos = gTranslator.fromUtf8(gTranslator.returnToDos(ps->reason()), u->userEncoding());
696 
697   if (ps->direct())
698   {
699     CPT_AckChatRefuse p(reasonDos, ps->sequence(), *u);
700     AckTCP(p, u->normalSocketDesc());
701   }
702   else
703   {
704     unsigned long nMsgID[2] = { ps->msgid1(), ps->msgid2() };
705     CPU_AckChatRefuse* p = new CPU_AckChatRefuse(*u, nMsgID, ps->sequence(), reasonDos);
706 		SendEvent_Server(p);
707 	}
708 }
709 
icqChatRequestAccept(const ProtoChatAcceptSignal * ps)710 void IcqProtocol::icqChatRequestAccept(const ProtoChatAcceptSignal* ps)
711 {
712   // basically a fancy tcp ack packet which is sent late
713   // add to history ??
714   UserWriteGuard u(ps->userId());
715   if (!u.isLocked())
716     return;
717   gLog.info(tr("Accepting chat request with %s (#%d)."), u->getAlias().c_str(), -ps->sequence());
718 
719   if (ps->direct())
720   {
721     CPT_AckChatAccept p(ps->port(), ps->clients(), ps->sequence(), *u, u->Version() > 7);
722     AckTCP(p, u->normalSocketDesc());
723   }
724   else
725   {
726     unsigned long nMsgID[2] = { ps->msgid1(), ps->msgid2() };
727     CPU_AckChatAccept* p = new CPU_AckChatAccept(*u, ps->clients(), nMsgID, ps->sequence(), ps->port());
728 		SendEvent_Server(p);
729 	}
730 }
731 
732 /*---------------------------------------------------------------------------
733  * OpenSSL stuff
734  *-------------------------------------------------------------------------*/
735 
icqOpenSecureChannel(const Licq::ProtocolSignal * ps)736 void IcqProtocol::icqOpenSecureChannel(const Licq::ProtocolSignal* ps)
737 {
738   if (!Licq::gDaemon.haveCryptoSupport())
739   {
740     gLog.warning(tr("icqOpenSecureChannel() to %s called when we do not support OpenSSL."),
741         ps->userId().toString().c_str());
742     return;
743   }
744 
745   UserWriteGuard u(ps->userId());
746   if (!u.isLocked())
747     return;
748 
749   CPT_OpenSecureChannel *pkt = new CPT_OpenSecureChannel(*u);
750   gLog.info(tr("Sending request for secure channel to %s (#%d)."),
751       u->getAlias().c_str(), -pkt->Sequence());
752   SendExpectEvent_Client(ps, *u, pkt, NULL);
753 
754   u->SetSendServer(false);
755 }
756 
icqCloseSecureChannel(const Licq::ProtocolSignal * ps)757 void IcqProtocol::icqCloseSecureChannel(const Licq::ProtocolSignal* ps)
758 {
759   if (!Licq::gDaemon.haveCryptoSupport())
760   {
761     gLog.warning(tr("icqCloseSecureChannel() to %s called when we do not support OpenSSL."),
762         ps->userId().toString().c_str());
763     return;
764   }
765 
766   UserWriteGuard u(ps->userId());
767   if (!u.isLocked())
768     return;
769 
770   CPT_CloseSecureChannel *pkt = new CPT_CloseSecureChannel(*u);
771   gLog.info(tr("Closing secure channel with %s (#%d)."),
772       u->getAlias().c_str(), -pkt->Sequence());
773   SendExpectEvent_Client(ps, *u, pkt, NULL);
774 
775   u->SetSendServer(false);
776 }
777 
icqOpenSecureChannelCancel(const Licq::UserId & userId,unsigned short nSequence)778 void IcqProtocol::icqOpenSecureChannelCancel(const Licq::UserId& userId,
779   unsigned short nSequence)
780 {
781   Licq::UserWriteGuard u(userId);
782   if (!u.isLocked())
783     return;
784   gLog.info(tr("Cancelling secure channel request to %s (#%d)."),
785       u->getAlias().c_str(), -nSequence);
786   // XXX Tear down tcp connection ??
787 }
788 
789 /*---------------------------------------------------------------------------
790  * Handshake
791  *
792  * Shake hands on the given socket with the given user.
793  *-------------------------------------------------------------------------*/
handshake_Send(DcSocket * s,const Licq::UserId & userId,unsigned short nPort,unsigned short nVersion,bool bConfirm,unsigned long nId)794 bool IcqProtocol::handshake_Send(DcSocket* s, const Licq::UserId& userId,
795    unsigned short nPort, unsigned short nVersion, bool bConfirm,
796    unsigned long nId)
797 {
798   s->SetVersion(nVersion);
799   s->setUserId(userId);
800 
801   unsigned long nUin = strtoul(userId.accountId().c_str(), NULL, 10);
802 
803   switch (nVersion)
804   {
805     case 2:
806     case 3:
807     {
808       CPacketTcp_Handshake_v2 p(s->getLocalPort());
809       if (!s->send(*p.getBuffer()))
810         goto sock_error;
811       break;
812     }
813     case 4:
814     case 5:
815     {
816       CPacketTcp_Handshake_v4 p(s->getLocalPort());
817       if (!s->send(*p.getBuffer()))
818         goto sock_error;
819       break;
820     }
821     case 6:
822     {
823       // Send the hanshake
824       CPacketTcp_Handshake_v6 p(nUin, 0, nPort);
825       if (!s->send(*p.getBuffer()))
826         goto sock_error;
827 
828       // Wait for the handshake ack
829       do
830       {
831         if (!s->RecvPacket()) goto sock_error;
832       } while (!s->RecvBufferFull());
833       s->RecvBuffer().unpackUInt16LE(); // Packet length
834       unsigned long nOk = s->RecvBuffer().UnpackUnsignedLong();
835       s->ClearRecvBuffer();
836       if (nOk != 1)
837       {
838         gLog.warning(tr("Bad handshake ack: %ld."), nOk);
839         return false;
840       }
841 
842       // Wait for the reverse handshake
843       do
844       {
845         if (!s->RecvPacket()) goto sock_error;
846       } while (!s->RecvBufferFull());
847       CPacketTcp_Handshake_v6 p_in(&s->RecvBuffer());
848       s->ClearRecvBuffer();
849       if (p.SessionId() != p_in.SessionId())
850       {
851         gLog.warning(tr("Bad handshake session id: received %ld, expecting %ld."),
852             p_in.SessionId(), p.SessionId());
853         return false;
854       }
855 
856       // Send the hanshake ack
857       CPacketTcp_Handshake_Ack p_ack;
858       if (!s->send(*p_ack.getBuffer()))
859         goto sock_error;
860 
861       break;
862     }
863 
864     case 7:
865     case 8:
866     {
867       // Send the hanshake
868       CPacketTcp_Handshake_v7 p(nUin, 0, nPort, nId);
869       if (!s->send(*p.getBuffer()))
870         goto sock_error;
871 
872       // Wait for the handshake ack
873       do
874       {
875         if (!s->RecvPacket()) goto sock_error;
876       } while (!s->RecvBufferFull());
877       s->RecvBuffer().unpackUInt16LE(); // Packet length
878       unsigned long nOk = s->RecvBuffer().UnpackUnsignedLong();
879       s->ClearRecvBuffer();
880       if (nOk != 1)
881       {
882         gLog.warning(tr("Bad handshake ack: %ld."), nOk);
883         return false;
884       }
885 
886       // Wait for the reverse handshake
887       do
888       {
889         if (!s->RecvPacket()) goto sock_error;
890       } while (!s->RecvBufferFull());
891       CPacketTcp_Handshake_v7 p_in(&s->RecvBuffer());
892       s->ClearRecvBuffer();
893       if (p_in.SessionId() && p.SessionId() != p_in.SessionId())
894       {
895         gLog.warning(tr("Bad handshake cookie: received %ld, expecting %ld."),
896             p_in.SessionId(), p.SessionId());
897         return false;
898       }
899 
900       // Send the hanshake ack
901       CPacketTcp_Handshake_Ack p_ack;
902       if (!s->send(*p_ack.getBuffer()))
903         goto sock_error;
904 
905 			// Files and chats don't get this.
906 			// They do in icq2002a but for some reason icq2002a does not
907 			// reply to this when licq sends it.  It will reply from a normal
908 			// handshake though, just not file or chat...
909 			if (bConfirm)
910 			{
911                           if (nId == 0)
912                           {
913                             if (!Handshake_SendConfirm_v7(s))
914                               return false;
915                           }
916                           else
917                           {
918                             if (!Handshake_RecvConfirm_v7(s))
919                               goto sock_error;
920                           }
921                         }
922 
923       break;
924     }
925 
926     default:
927       // Should never happen
928       gLog.error(tr("Unknown ICQ TCP version (%d)."), nVersion);
929       return false;
930   }
931 
932   return true;
933 
934 sock_error:
935   if (s->Error() == 0)
936     gLog.warning(tr("Handshake error, remote side closed connection."));
937   else
938     gLog.warning(tr("Handshake socket error: %s."), s->errorStr().c_str());
939   return false;
940 }
941 
942 
943 /*------------------------------------------------------------------------------
944  * ConnectToUser
945  *
946  * Creates a new TCPSocket and connects it to a given user.  Adds the socket
947  * to the global socket manager and to the user.
948  *----------------------------------------------------------------------------*/
connectToUser(const Licq::UserId & userId,int channel)949 int IcqProtocol::connectToUser(const Licq::UserId& userId, int channel)
950 {
951   {
952     UserReadGuard u(userId);
953     if (!u.isLocked())
954       return -1;
955 
956     // Check that we need to connect at all
957     int sd = u->socketDesc(channel);
958     if (sd != -1)
959     {
960       gLog.warning(tr("Connection attempted to already connected user (%s)."),
961           userId.toString().c_str());
962       return sd;
963     }
964   }
965 
966   // Poll if there is a connection in progress already
967   while (1)
968   {
969     {
970       Licq::UserReadGuard u(userId);
971       if (u.isLocked() && !u->ConnectionInProgress())
972         break;
973     }
974     struct timeval tv = { 2, 0 };
975     if (select(0, NULL, NULL, NULL, &tv) == -1 && errno == EINTR) return -1;
976   }
977 
978   string alias;
979   unsigned nPort;
980   unsigned nVersion;
981 
982   {
983     UserWriteGuard u(userId);
984     int sd = u->normalSocketDesc();
985     if (sd == -1)
986       u->SetConnectionInProgress(true);
987     else
988       return sd;
989 
990     alias = u->getAlias();
991     nPort = u->Port();
992     nVersion = u->ConnectionVersion();
993   }
994 
995   DcSocket* s = new DcSocket(userId);
996   if (!openConnectionToUser(userId, s, nPort))
997   {
998     Licq::UserWriteGuard u(userId);
999     if (u.isLocked())
1000       u->SetConnectionInProgress(false);
1001     delete s;
1002     return -1;
1003   }
1004   s->setChannel(channel);
1005 
1006   gLog.info(tr("Shaking hands with %s (%s) [v%d]."),
1007       alias.c_str(), userId.toString().c_str(), nVersion);
1008   nPort = s->getLocalPort();
1009 
1010   if (!handshake_Send(s, userId, 0, nVersion))
1011   {
1012     Licq::UserWriteGuard u(userId);
1013     if (u.isLocked())
1014       u->SetConnectionInProgress(false);
1015     delete s;
1016     return -1;
1017   }
1018   s->SetVersion(nVersion);
1019   int nSD = s->Descriptor();
1020 
1021   // Set the socket descriptor in the user
1022   {
1023     UserWriteGuard u(userId);
1024     if (!u.isLocked())
1025       return -1;
1026     u->setSocketDesc(s);
1027     u->SetConnectionInProgress(false);
1028   }
1029 
1030   // Add the new socket to the socket manager
1031   gSocketManager.AddSocket(s);
1032   gSocketManager.DropSocket(s);
1033 
1034   // Alert the select thread that there is a new socket
1035   myNewSocketPipe.putChar('S');
1036 
1037   return nSD;
1038 }
1039 
1040 
1041 
1042 /*------------------------------------------------------------------------------
1043  * OpenConnectionToUser
1044  *
1045  * Connects a socket to a given user on a given port.
1046  *----------------------------------------------------------------------------*/
openConnectionToUser(const Licq::UserId & userId,Licq::TCPSocket * sock,unsigned short nPort)1047 bool IcqProtocol::openConnectionToUser(const Licq::UserId& userId,
1048     Licq::TCPSocket* sock, unsigned short nPort)
1049 {
1050   string name;
1051   unsigned long ip;
1052   unsigned long intip;
1053   bool bSendIntIp;
1054   {
1055     Licq::UserReadGuard u(userId);
1056     if (!u.isLocked())
1057       return false;
1058 
1059     name = u->getAlias() + " (" + u->accountId() + ")";
1060     ip = u->Ip();
1061     intip = u->IntIp();
1062     bSendIntIp = u->SendIntIp();
1063   }
1064 
1065   return OpenConnectionToUser(name, ip, intip, sock, nPort, bSendIntIp);
1066 }
1067 
1068 
OpenConnectionToUser(const string & name,unsigned long nIp,unsigned long nIntIp,Licq::TCPSocket * sock,unsigned short nPort,bool bSendIntIp)1069 bool IcqProtocol::OpenConnectionToUser(const string& name, unsigned long nIp,
1070    unsigned long nIntIp, Licq::TCPSocket* sock, unsigned short nPort, bool bSendIntIp)
1071 {
1072   char buf[128];
1073 
1074   // Sending to internet ip
1075   if (!bSendIntIp)
1076   {
1077     gLog.info(tr("Connecting to %s at %s:%d."), name.c_str(),
1078         Licq::ip_ntoa(nIp, buf), nPort);
1079     // If we fail to set the remote address, the ip must be 0
1080     if (!sock->connectTo(nIp, nPort))
1081     {
1082       gLog.warning(tr("Connect to %s failed: %s."), name.c_str(),
1083           sock->errorStr().c_str());
1084 
1085       // Now try the internal ip if it is different from this one and we are behind a firewall
1086       if (sock->Error() != EINTR && nIntIp != nIp &&
1087           nIntIp != 0 && CPacket::Firewall())
1088       {
1089         gLog.info(tr("Connecting to %s at %s:%d."), name.c_str(),
1090             Licq::ip_ntoa(nIntIp, buf), nPort);
1091 
1092         if (!sock->connectTo(nIntIp, nPort))
1093         {
1094           gLog.warning(tr("Connect to %s real ip failed: %s."), name.c_str(),
1095               sock->errorStr().c_str());
1096           return false;
1097         }
1098       }
1099       else
1100       {
1101         return false;
1102       }
1103     }
1104   }
1105 
1106   // Sending to Internal IP
1107   else
1108   {
1109     gLog.info(tr("Connecting to %s at %s:%d."), name.c_str(),
1110        Licq::ip_ntoa(nIntIp, buf), nPort);
1111     if (!sock->connectTo(nIntIp, nPort))
1112     {
1113       gLog.warning(tr("Connect to %s real ip failed: %s."), name.c_str(),
1114           sock->errorStr().c_str());
1115       return false;
1116     }
1117   }
1118 
1119 
1120   return true;
1121 }
1122 
1123 
1124 
1125 /*------------------------------------------------------------------------------
1126  * ReverseConnectToUser
1127  *
1128  * Creates a new TCPSocket and connects it to a given user.  Adds the socket
1129  * to the global socket manager and to the user.
1130  *----------------------------------------------------------------------------*/
reverseConnectToUser(const Licq::UserId & userId,unsigned long nIp,unsigned short nPort,unsigned short nVersion,unsigned short nFailedPort,unsigned long nId,unsigned long nMsgID1,unsigned long nMsgID2)1131 int IcqProtocol::reverseConnectToUser(const Licq::UserId& userId, unsigned long nIp,
1132    unsigned short nPort, unsigned short nVersion, unsigned short nFailedPort,
1133    unsigned long nId, unsigned long nMsgID1, unsigned long nMsgID2)
1134 {
1135   FileTransferManager* ftm = FileTransferManager::FindByPort(nFailedPort);
1136   ChatManager *cm = ChatManager::FindByPort(nFailedPort);
1137 
1138   DcSocket* s = new DcSocket(userId);
1139   char buf[32];
1140 
1141   gLog.info(tr("Reverse connecting to %s at %s:%d."), userId.toString().c_str(),
1142       Licq::ip_ntoa(nIp, buf), nPort);
1143 
1144   // If we fail to set the remote address, the ip must be 0
1145   if (!s->connectTo(nIp, nPort))
1146   {
1147     gLog.warning(tr("Reverse connect to %s failed: %s."),
1148         userId.toString().c_str(), s->errorStr().c_str());
1149 
1150     CPU_ReverseConnectFailed* p = new CPU_ReverseConnectFailed(userId.accountId(), nMsgID1,
1151         nMsgID2, nPort, nFailedPort, nId);
1152     SendEvent_Server(p);
1153     return -1;
1154   }
1155 
1156   gLog.info(tr("Reverse shaking hands with %s."), userId.toString().c_str());
1157   bool bConfirm = ftm == NULL && cm == NULL;
1158 
1159   // Make sure we use the right version
1160   nVersion = IcqProtocol::dcVersionToUse(nVersion);
1161 
1162   if (!handshake_Send(s, userId, 0, nVersion, bConfirm, nId))
1163   {
1164     delete s;
1165     return -1;
1166   }
1167   s->SetVersion(nVersion);
1168   int nSD = s->Descriptor();
1169 
1170   // File transfer port
1171   if (ftm != NULL)
1172   {
1173      ftm->AcceptReverseConnection(s);
1174      delete s;
1175   }
1176 
1177   // Chat port
1178   else if (cm != NULL)
1179   {
1180      cm->AcceptReverseConnection(s);
1181      delete s;
1182   }
1183 
1184   // It's the main port
1185   else
1186   {
1187     // Set the socket descriptor in the user if this user is on our list
1188     {
1189       UserWriteGuard u(userId);
1190       if (u.isLocked())
1191         u->setSocketDesc(s);
1192     }
1193 
1194     // Add the new socket to the socket manager, alert the thread
1195     gSocketManager.AddSocket(s);
1196     gSocketManager.DropSocket(s);
1197     myNewSocketPipe.putChar('S');
1198   }
1199 
1200   return nSD;
1201 }
1202 
ProcessTcpPacket(DcSocket * pSock)1203 bool IcqProtocol::ProcessTcpPacket(DcSocket* pSock)
1204 {
1205   unsigned long senderIp, localIp,
1206                 senderPort, junkLong, nPort, nPortReversed;
1207   unsigned short version, command, junkShort, newCommand, messageLen,
1208                  headerLen, ackFlags, msgFlags, licqVersion, theSequence;
1209   char licqChar = '\0', junkChar;
1210   bool errorOccured = false;
1211   Licq::UserId userId;
1212 
1213   // only used for v7,v8
1214 	headerLen = 0;
1215 
1216   CBuffer &packet = pSock->RecvBuffer();
1217   int sockfd = pSock->Descriptor();
1218 
1219   unsigned short nInVersion = pSock->Version();
1220 
1221   switch (nInVersion)
1222   {
1223     case 1:
1224     case 2:
1225     case 3:
1226     {
1227       packet.unpackUInt16LE(); // Packet length
1228       unsigned long nUin;
1229       packet >> nUin
1230              >> version
1231              >> command      // main tcp command (start, cancel, ack)
1232              >> junkShort    // 00 00 to fill in the MSB of the command long int which is read in as a short
1233              >> nUin
1234              >> newCommand   // sub command (message/chat/read away message/...)
1235              >> messageLen   // length of incoming message
1236       ;
1237       char id[16];
1238       snprintf(id, 15, "%lu", nUin);
1239       userId = Licq::UserId(myOwnerId, id);
1240       break;
1241     }
1242     case 4:
1243     case 5:
1244     {
1245       if (!Decrypt_Client(&packet, 4))
1246       {
1247         packet.log(Log::Unknown, "Invalid TCPv4 encryption");
1248         return false;
1249       }
1250       packet.unpackUInt16LE(); // Packet length
1251       unsigned long nUin;
1252       packet >> nUin
1253              >> version
1254              >> junkLong     // checksum
1255              >> command      // main tcp command (start, cancel, ack)
1256              >> junkShort    // 00 00 to fill in the MSB of the command long int which is read in as a short
1257              >> nUin
1258              >> newCommand   // sub command (message/chat/read away message/...)
1259              >> messageLen   // length of incoming message
1260       ;
1261       char id[16];
1262       snprintf(id, 15, "%lu", nUin);
1263       userId = Licq::UserId(myOwnerId, id);
1264       break;
1265     }
1266     case 6:
1267     {
1268       userId = pSock->userId();
1269       if (!Decrypt_Client(&packet, 6))
1270       {
1271         packet.log(Log::Unknown, "Invalid TCPv6 encryption");
1272         return false;
1273       }
1274       packet.unpackUInt16LE(); // Packet length
1275       packet.UnpackUnsignedLong(); // Checksum
1276       command = packet.UnpackUnsignedShort(); // Command
1277       packet.UnpackUnsignedShort(); // 0x000E
1278       theSequence = (signed short)packet.UnpackUnsignedShort();
1279       unsigned long junkLong1, junkLong2, junkLong3;
1280       packet >> junkLong1 >> junkLong2 >> junkLong3; // maybe always zero ??!
1281       newCommand = packet.UnpackUnsignedShort();
1282       ackFlags = packet.UnpackUnsignedShort();
1283       msgFlags = packet.UnpackUnsignedShort();
1284       packet >> messageLen;
1285       break;
1286     }
1287     case 7:
1288     case 8:
1289     {
1290       userId = pSock->userId();
1291       if (!Decrypt_Client(&packet, nInVersion))
1292       {
1293         packet.log(Log::Unknown, "Unknown TCPv%d packet", nInVersion);
1294         break;
1295       }
1296       packet.unpackUInt16LE(); // Packet length
1297       packet.UnpackChar(); // 0x02
1298       packet.UnpackUnsignedLong(); // Checksum
1299       command = packet.UnpackUnsignedShort(); // Command
1300       headerLen = packet.UnpackUnsignedShort();
1301       theSequence = (signed short)packet.UnpackUnsignedShort();
1302       packet.incDataPosRead(headerLen - 2);
1303       newCommand = packet.UnpackUnsignedShort();
1304 
1305       if (pSock->channel() == DcSocket::ChannelNormal)
1306       {
1307         ackFlags = packet.UnpackUnsignedShort();
1308         msgFlags = packet.UnpackUnsignedShort();
1309         packet >> messageLen;
1310 
1311         // Stupid AOL
1312         if (msgFlags & ICQ_TCPxMSG_URGENT2)
1313           msgFlags |= ICQ_TCPxMSG_URGENT;
1314         if (msgFlags & ICQ_TCPxMSG_LIST2)
1315           msgFlags |= ICQ_TCPxMSG_LIST;
1316       }
1317 
1318       break;
1319     }
1320     default:
1321     {
1322       gLog.warning(tr("Unknown TCP version %d from socket."), nInVersion);
1323       break;
1324     }
1325   }
1326 
1327   // Some simple validation of the packet
1328   if (!userId.isValid() || command == 0)
1329   {
1330     packet.log(Log::Unknown, "Invalid TCP packet (uin: %s, cmd: %04x)",
1331                userId.toString().c_str(), command);
1332     return false;
1333   }
1334 
1335   if (userId.isOwner())
1336   {
1337     packet.log(Log::Warning, tr("TCP message from self (probable spoof)"));
1338     return false;
1339   }
1340   if (userId != pSock->userId())
1341   {
1342     packet.log(Log::Warning, tr("TCP message from invalid UIN (%s, expect %s)"),
1343         userId.toString().c_str(), pSock->userId().toString().c_str());
1344     return false;
1345   }
1346 
1347   // Store our status for later use
1348   unsigned ownerStatus;
1349   {
1350     Licq::OwnerReadGuard o(myOwnerId);
1351     ownerStatus = o->status();
1352   }
1353 
1354   // find which user was sent
1355   bool bNewUser = false;
1356   UserWriteGuard u(userId, true, &bNewUser);
1357   if (bNewUser)
1358     u->setSocketDesc(pSock);
1359 
1360   // Check for spoofing
1361   if (u->socketDesc(pSock->channel()) != sockfd)
1362   {
1363     gLog.warning(tr("User %s (%s) socket (%d) does not match incoming message (%d)."),
1364         u->getAlias().c_str(), u->accountId().c_str(),
1365               u->socketDesc(pSock->channel()), sockfd);
1366   }
1367 
1368   if (pSock->channel() != DcSocket::ChannelNormal)
1369   {
1370     errorOccured = processPluginMessage(packet, *u, pSock->channel(),
1371                                         command == ICQ_CMDxTCP_ACK,
1372                                         0, 0, theSequence, pSock);
1373   }
1374   else
1375   {
1376 
1377   // read in the message minus any stupid DOS \r's
1378     string message = parseRtf(gTranslator.returnToUnix(packet.unpackRawString(messageLen)));
1379 
1380     if (nInVersion < 6)
1381     {
1382     // read in some more stuff common to all tcp packets
1383     packet >> senderIp
1384            >> localIp
1385            >> senderPort
1386            >> junkChar      // whether use can receive tcp packets directly
1387            >> ackFlags
1388            >> msgFlags
1389     ;
1390     senderIp = LE_32(senderIp);
1391     localIp = LE_32(localIp);
1392   }
1393 
1394   unsigned long nMask = Licq::UserEvent::FlagDirect |
1395       ((newCommand & ICQ_CMDxSUB_FxMULTIREC) ? (int)Licq::UserEvent::FlagMultiRec : 0) |
1396       ((msgFlags & ICQ_TCPxMSG_URGENT) ? (int)Licq::UserEvent::FlagUrgent : 0) |
1397       (pSock->Secure() ? (int)Licq::UserEvent::FlagEncrypted : 0);
1398   newCommand &= ~ICQ_CMDxSUB_FxMULTIREC;
1399   bool bAccept = msgFlags & ICQ_TCPxMSG_URGENT || msgFlags & ICQ_TCPxMSG_LIST;
1400   // Flag as sent urgent as well if we are in occ or dnd and auto-accept is on
1401   if ( (((ownerStatus & Licq::User::OccupiedStatus) || (u->statusToUser() & Licq::User::OccupiedStatus))
1402           && u->AcceptInOccupied() ) ||
1403       (((ownerStatus & Licq::User::DoNotDisturbStatus) || (u->statusToUser() & Licq::User::DoNotDisturbStatus))
1404           && u->AcceptInDND() ) ||
1405       (u->statusToUser() != Licq::User::OfflineStatus
1406           && (u->statusToUser() & (Licq::User::OccupiedStatus | Licq::User::DoNotDisturbStatus)) == 0) )
1407     bAccept = true;
1408 
1409   //fprintf(stderr, "status: %04X (%04X)  msgtype: %04X\n", ackFlags, u->Status(), msgFlags);
1410 
1411   switch(command)
1412   {
1413 
1414   //-----START------------------------------------------------------------------
1415   case ICQ_CMDxTCP_START:
1416   {
1417     // Process the status bits
1418     unsigned short s = 0, ns = 0;
1419 
1420     // Stupid AOL
1421     if (nInVersion >= 7)
1422     {
1423       s = 0;
1424       ns = ackFlags;
1425     }
1426     else
1427       s = msgFlags & 0xFF80;
1428 
1429     if (s & ICQ_TCPxMSG_FxINVISIBLE)
1430     {
1431       s &= ~ICQ_TCPxMSG_FxINVISIBLE;
1432       ns |= ICQ_STATUS_FxPRIVATE;
1433     }
1434     switch(s)
1435     {
1436       case ICQ_TCPxMSG_FxONLINE: ns |= ICQ_STATUS_ONLINE; break;
1437       case ICQ_TCPxMSG_FxAWAY: ns |= ICQ_STATUS_AWAY; break;
1438       case ICQ_TCPxMSG_FxOCCUPIED: ns |= ICQ_STATUS_OCCUPIED; break;
1439       case ICQ_TCPxMSG_FxNA: ns |= ICQ_STATUS_NA; break;
1440       case ICQ_TCPxMSG_FxDND: ns |= ICQ_STATUS_DND; break;
1441       default:
1442         ns = ICQ_STATUS_OFFLINE;
1443           gLog.warning(tr("Unknown TCP status: %04X"), msgFlags);
1444           break;
1445       }
1446       //fprintf(stderr, "%08lX\n", addStatusFlags(ns, u));
1447     /*if (!bNewUser && ns != ICQ_STATUS_OFFLINE &&
1448         !((ns & ICQ_STATUS_FxPRIVATE) && !u->isOnline()))*/
1449     if (!bNewUser && ns != ICQ_STATUS_OFFLINE &&
1450           !(ns == ICQ_STATUS_ONLINE && (u->status() & Licq::User::FreeForChatStatus)) &&
1451           ns != (icqStatusFromStatus(u->status()) | (u->isInvisible() ? ICQ_STATUS_FxPRIVATE : 0)))
1452       {
1453       bool r = u->OfflineOnDisconnect() || !u->isOnline();
1454         u->statusChanged(statusFromIcqStatus(ns));
1455         gLog.info(tr("%s (%s) is %s to us."), u->getAlias().c_str(),
1456             u->id().toString().c_str(), u->statusString().c_str());
1457       if (r) u->SetOfflineOnDisconnect(true);
1458     }
1459 
1460     // Process the command
1461     switch(newCommand)
1462     {
1463       case ICQ_CMDxSUB_MSG:  // straight message from a user
1464       {
1465         unsigned long back = 0xFFFFFF, fore = 0x000000;
1466           bool isUtf8 = false;
1467             if (nInVersion < 6)
1468             {
1469           if (packet.getDataPosRead() + 4 >
1470                               (packet.getDataStart() + packet.getDataSize()))
1471           {
1472             theSequence = (signed short)packet.UnpackUnsignedShort();
1473           }
1474           else
1475             packet >> theSequence;
1476 
1477               packet >> licqChar >> licqVersion;
1478               nMask |= licqVersion;
1479             }
1480             else
1481             {
1482           packet >> fore >> back;
1483           if( fore == back ) {
1484             back = 0xFFFFFF;
1485             fore = 0x000000;
1486           }
1487 
1488               // Check if message is marked as UTF8
1489               unsigned long guidlen;
1490               packet >> guidlen;
1491             while (guidlen >= 38)
1492             {
1493               string guid = packet.unpackRawString(38);
1494               if (guid == ICQ_CAPABILITY_UTF8_STR)
1495                 isUtf8 = true;
1496               guidlen -= 38;
1497             }
1498           }
1499 
1500 				if (licqChar == 'L')
1501             gLog.info(tr("Message from %s (%s) [Licq %s]."),
1502                 u->getAlias().c_str(), userId.toString().c_str(),
1503                 Licq::UserEvent::licqVersionToString(licqVersion).c_str());
1504 	  else
1505             gLog.info(tr("Message from %s (%s)."), u->getAlias().c_str(), userId.toString().c_str());
1506 
1507           CPT_AckGeneral p(newCommand, theSequence, true, bAccept, *u);
1508         AckTCP(p, pSock);
1509 
1510           Licq::EventMsg* e = new Licq::EventMsg(
1511               (isUtf8 ? message : gTranslator.toUtf8(message, u->userEncoding())),
1512               Licq::EventMsg::TimeNow, nMask);
1513         e->SetColor(fore, back);
1514 
1515         // If we are in DND or Occupied and message isn't urgent then we ignore it
1516         if (!bAccept)
1517         {
1518             if (ownerStatus & (Licq::User::OccupiedStatus | Licq::User::DoNotDisturbStatus))
1519             {
1520             delete e;
1521             break;
1522           }
1523         }
1524         // Add the user to our list if they are new
1525         if (bNewUser)
1526         {
1527             if (gDaemon.ignoreType(Daemon::IgnoreNewUsers))
1528             {
1529             // FIXME should log a message here or in reject event
1530             // FIXME should either refuse the event or have a special auto response
1531             // for rejected events instead of pretending to accept the user
1532               gDaemon.rejectEvent(userId, e);
1533               break;
1534             }
1535           bNewUser = false;
1536         }
1537 
1538           if (!gDaemon.addUserEvent(*u, e))
1539             break;
1540           gOnEventManager.performOnEvent(OnEventData::OnEventMessage, *u);
1541           break;
1542         }
1543       case ICQ_CMDxTCP_READxNAxMSG:
1544       case ICQ_CMDxTCP_READxDNDxMSG:
1545       case ICQ_CMDxTCP_READxOCCUPIEDxMSG:
1546       case ICQ_CMDxTCP_READxFFCxMSG:
1547       case ICQ_CMDxTCP_READxAWAYxMSG:  // read away message
1548           {
1549             if (nInVersion < 6)
1550             {
1551           if (packet.getDataPosRead() + 4 >
1552                               (packet.getDataStart() + packet.getDataSize()))
1553           {
1554             theSequence = (signed short)packet.UnpackUnsignedShort();
1555           }
1556           else
1557             packet >> theSequence;
1558 
1559               packet >> licqChar >> licqVersion;
1560             }
1561             else
1562           packet >> junkLong >> junkLong;
1563 
1564         if (licqChar == 'L')
1565             gLog.info(tr("%s (%s) requested auto response [Licq %s]."),
1566                 u->getAlias().c_str(), userId.toString().c_str(),
1567                 Licq::UserEvent::licqVersionToString(licqVersion).c_str());
1568           else
1569             gLog.info(tr("%s (%s) requested auto response."), u->getAlias().c_str(), userId.toString().c_str());
1570 
1571           CPT_AckGeneral p(newCommand, theSequence, true, false, *u);
1572         AckTCP(p, pSock);
1573 
1574           Licq::gStatistics.increase(Licq::Statistics::AutoResponseCheckedCounter);
1575         u->SetLastCheckedAutoResponse();
1576 
1577           Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
1578               Licq::PluginSignal::SignalUser,
1579               Licq::PluginSignal::UserEvents, u->id()));
1580           break;
1581       }
1582 
1583       case ICQ_CMDxSUB_URL:  // url sent
1584       {
1585         unsigned long back = 0xFFFFFF, fore = 0x000000;
1586             if (nInVersion < 6)
1587             {
1588           if (packet.getDataPosRead() + 4 >
1589                               (packet.getDataStart() + packet.getDataSize()))
1590           {
1591             theSequence = (signed short)packet.UnpackUnsignedShort();
1592           }
1593           else
1594             packet >> theSequence;
1595 
1596               packet >> licqChar >> licqVersion;
1597               nMask |= licqVersion;
1598             }
1599             else
1600             {
1601           packet >> fore >> back;
1602           if(fore == back)
1603           {
1604             fore = 0x000000;
1605             back = 0xFFFFFF;
1606           }
1607         }
1608         if (licqChar == 'L')
1609             gLog.info(tr("URL from %s (%s) [Licq %s]."), u->getAlias().c_str(),
1610                 userId.toString().c_str(), Licq::UserEvent::licqVersionToString(licqVersion).c_str());
1611           else
1612             gLog.info(tr("URL from %s (%s)."), u->getAlias().c_str(), userId.toString().c_str());
1613 
1614           Licq::EventUrl* e = parseUrlEvent(message, Licq::EventUrl::TimeNow, nMask, u->userEncoding());
1615         if (e == NULL)
1616         {
1617           packet.log(Log::Warning, tr("Invalid URL message"));
1618           errorOccured = true;
1619           break;
1620         }
1621         e->SetColor(fore, back);
1622 
1623           CPT_AckGeneral p(newCommand, theSequence, true, bAccept, *u);
1624         AckTCP(p, pSock);
1625 
1626         // If we are in DND or Occupied and message isn't urgent then we ignore it
1627         if (!bAccept)
1628         {
1629             if (ownerStatus & (Licq::User::OccupiedStatus | Licq::User::DoNotDisturbStatus))
1630             {
1631             delete e;
1632             break;
1633           }
1634         }
1635         // Add the user to our list if they are new
1636         if (bNewUser)
1637         {
1638             if (gDaemon.ignoreType(Daemon::IgnoreNewUsers))
1639             {
1640               gDaemon.rejectEvent(userId, e);
1641               break;
1642             }
1643           bNewUser = false;
1644         }
1645 
1646           if (!gDaemon.addUserEvent(*u, e))
1647             break;
1648           gOnEventManager.performOnEvent(OnEventData::OnEventUrl, *u);
1649           break;
1650         }
1651 
1652       // Contact List
1653       case ICQ_CMDxSUB_CONTACTxLIST:
1654       {
1655         unsigned long back = 0xFFFFFF, fore = 0x000000;
1656             if (nInVersion < 6)
1657             {
1658           if (packet.getDataPosRead() + 4 >
1659                               (packet.getDataStart() + packet.getDataSize()))
1660           {
1661             theSequence = (signed short)packet.UnpackUnsignedShort();
1662           }
1663           else
1664             packet >> theSequence;
1665 
1666               packet >> licqChar >> licqVersion;
1667               nMask |= licqVersion;
1668             }
1669             else
1670             {
1671           packet >> fore >> back;
1672           if(fore == back) {
1673             fore = 0x000000;
1674             back = 0xFFFFFF;
1675           }
1676         }
1677         if (licqChar == 'L')
1678             gLog.info(tr("Contact list from %s (%s) [Licq %s]."),
1679                 u->getAlias().c_str(), userId.toString().c_str(),
1680                 Licq::UserEvent::licqVersionToString(licqVersion).c_str());
1681           else
1682             gLog.info(tr("Contact list from %s (%s).\n"),
1683                 u->getAlias().c_str(), userId.toString().c_str());
1684 
1685           Licq::EventContactList* e = parseContactEvent(message, Licq::EventContactList::TimeNow,
1686               nMask, u->userEncoding());
1687         if (e == NULL)
1688         {
1689           packet.log(Log::Warning, tr("Invalid contact list message"));
1690           errorOccured = true;
1691           break;
1692         }
1693         e->SetColor(fore, back);
1694 
1695           CPT_AckGeneral p(newCommand, theSequence, true, bAccept, *u);
1696         AckTCP(p, pSock);
1697 
1698         // If we are in DND or Occupied and message isn't urgent then we ignore it
1699         if (!bAccept)
1700         {
1701             if (ownerStatus & (Licq::User::OccupiedStatus | Licq::User::DoNotDisturbStatus))
1702             {
1703             delete e;
1704             break;
1705           }
1706         }
1707         // Add the user to our list if they are new
1708         if (bNewUser)
1709         {
1710             if (gDaemon.ignoreType(Daemon::IgnoreNewUsers))
1711             {
1712               gDaemon.rejectEvent(userId, e);
1713               break;
1714             }
1715           bNewUser = false;
1716         }
1717 
1718           if (!gDaemon.addUserEvent(*u, e))
1719             break;
1720           gOnEventManager.performOnEvent(OnEventData::OnEventMessage, *u);
1721           break;
1722         }
1723 
1724       // Chat Request
1725       case ICQ_CMDxSUB_CHAT:
1726       {
1727           string msgUtf8 = gTranslator.toUtf8(message, u->userEncoding());
1728 
1729           string chatClients = packet.unpackShortStringLE();
1730         packet.UnpackUnsignedLong(); // reversed port
1731         unsigned short nPort = packet.UnpackUnsignedLong();
1732             if (nInVersion < 6)
1733             {
1734           if (packet.getDataPosRead() + 4 >
1735                               (packet.getDataStart() + packet.getDataSize()))
1736           {
1737             theSequence = (signed short)packet.UnpackUnsignedShort();
1738           }
1739           else
1740             packet >> theSequence;
1741 
1742               packet >> licqChar >> licqVersion;
1743             }
1744 
1745         if (licqChar == 'L')
1746             gLog.info(tr("Chat request from %s (%s) [Licq %s]."),
1747                 u->getAlias().c_str(), userId.toString().c_str(),
1748                 Licq::UserEvent::licqVersionToString(licqVersion).c_str());
1749           else
1750             gLog.info(tr("Chat request from %s (%s)."),
1751                 u->getAlias().c_str(), userId.toString().c_str());
1752 
1753           Licq::EventChat* e = new Licq::EventChat(msgUtf8, chatClients, nPort, theSequence,
1754               Licq::EventChat::TimeNow, nMask | licqVersion);
1755 
1756         // Add the user to our list if they are new
1757         if (bNewUser)
1758         {
1759             if (gDaemon.ignoreType(Daemon::IgnoreNewUsers))
1760             {
1761               gDaemon.rejectEvent(userId, e);
1762               break;
1763             }
1764           bNewUser = false;
1765         }
1766 
1767           if (!gDaemon.addUserEvent(*u, e))
1768             break;
1769           gOnEventManager.performOnEvent(OnEventData::OnEventChat, *u);
1770           break;
1771         }
1772 
1773       // File transfer
1774       case ICQ_CMDxSUB_FILE:
1775       {
1776           string msgUtf8 = gTranslator.toUtf8(message, u->userEncoding());
1777 
1778         unsigned long nFileLength;
1779           packet.UnpackUnsignedLong();
1780           string filename = packet.unpackShortStringLE();
1781         packet >> nFileLength
1782                >> junkLong;
1783             if (nInVersion < 6)
1784             {
1785           if (packet.getDataPosRead() + 4 >
1786                               (packet.getDataStart() + packet.getDataSize()))
1787           {
1788             theSequence = (signed short)packet.UnpackUnsignedShort();
1789           }
1790           else
1791             packet >> theSequence;
1792 
1793               packet >> licqChar >> licqVersion;
1794             }
1795 
1796         if (licqChar == 'L')
1797             gLog.info(tr("File transfer request from %s (%s) [Licq %s]."),
1798                 u->getAlias().c_str(), userId.toString().c_str(),
1799                 Licq::UserEvent::licqVersionToString(licqVersion).c_str());
1800           else
1801             gLog.info(tr("File transfer request from %s (%s)."),
1802                 u->getAlias().c_str(), userId.toString().c_str());
1803 
1804         list<string> filelist;
1805         filelist.push_back(filename);
1806 
1807           Licq::EventFile* e = new Licq::EventFile(filename, msgUtf8, nFileLength,
1808               filelist, theSequence, Licq::EventFile::TimeNow, nMask | licqVersion);
1809         // Add the user to our list if they are new
1810         if (bNewUser)
1811         {
1812             if (gDaemon.ignoreType(Daemon::IgnoreNewUsers))
1813             {
1814               gDaemon.rejectEvent(userId, e);
1815               break;
1816             }
1817           bNewUser = false;
1818         }
1819 
1820           if (!gDaemon.addUserEvent(*u, e))
1821             break;
1822           gOnEventManager.performOnEvent(OnEventData::OnEventFile, *u);
1823           break;
1824         }
1825 
1826 			// Yuck, ICBM
1827 			// XXX If we are in DND or OCC, don't accept the message!
1828 			case ICQ_CMDxSUB_ICBM:
1829 			{
1830 				unsigned short nLen;
1831 				packet >> nLen;
1832 				packet.incDataPosRead(18);
1833 
1834           string plugin = packet.unpackLongStringLE();
1835 
1836 				packet.incDataPosRead(nLen - 22 - plugin.size());
1837 				packet.incDataPosRead(4); // bytes left in packet
1838 
1839 				int nICBMCommand = 0;
1840           if (plugin.find("File") != string::npos)
1841 					nICBMCommand = ICQ_CMDxSUB_FILE;
1842           else if (plugin.find("URL") != string::npos)
1843 					nICBMCommand = ICQ_CMDxSUB_URL;
1844           else if (plugin.find("Chat") != string::npos)
1845 					nICBMCommand = ICQ_CMDxSUB_CHAT;
1846           else if (plugin.find("Contacts") != string::npos)
1847 					nICBMCommand = ICQ_CMDxSUB_CONTACTxLIST;
1848           else
1849           {
1850             gLog.info(tr("Unknown ICBM plugin type: %s"), plugin.c_str());
1851             break;
1852           }
1853 
1854             string icbmMessage = packet.unpackLongStringLE();
1855 
1856 				switch (nICBMCommand)
1857 				{
1858 				case ICQ_CMDxSUB_FILE:
1859               {
1860                 icbmMessage = gTranslator.toUtf8(icbmMessage, u->userEncoding());
1861 
1862 					unsigned long nFileSize;
1863 					packet.incDataPosRead(2); // port (BE)
1864 					packet.incDataPosRead(2); // unknown
1865                 string filename = packet.unpackShortStringLE();
1866 					packet >> nFileSize;
1867 					packet.incDataPosRead(2); // reversed port (BE)
1868 
1869               gLog.info(tr("File transfer request from %s (%s)."),
1870                   u->getAlias().c_str(), userId.toString().c_str());
1871 
1872               list<string> filelist;
1873               filelist.push_back(filename);
1874                 Licq::EventFile* e = new Licq::EventFile(filename, icbmMessage, nFileSize,
1875                     filelist, theSequence, Licq::EventFile::TimeNow, nMask);
1876 					if (bNewUser)
1877 					{
1878                   if (gDaemon.ignoreType(Daemon::IgnoreNewUsers))
1879                   {
1880                   gDaemon.rejectEvent(userId, e);
1881                   break;
1882                 }
1883 						bNewUser = false;
1884 					}
1885 
1886                 if (!gDaemon.addUserEvent(*u, e))
1887                   break;
1888                 gOnEventManager.performOnEvent(OnEventData::OnEventFile, *u);
1889                 break;
1890               }
1891               case ICQ_CMDxSUB_CHAT:
1892               {
1893                 icbmMessage = gTranslator.toUtf8(icbmMessage, u->userEncoding());
1894                 string chatClients = packet.unpackShortStringLE();
1895 					nPort = packet.UnpackUnsignedShortBE();
1896 					packet >> nPortReversed;
1897 
1898 					if (nPort == 0)
1899 						nPort = nPortReversed;
1900 
1901               gLog.info(tr("Chat request from %s (%s)."),
1902                   u->getAlias().c_str(), userId.toString().c_str());
1903 
1904                 Licq::EventChat* e = new Licq::EventChat(icbmMessage, chatClients, nPort,
1905                     theSequence, Licq::EventChat::TimeNow, nMask);
1906 					if (bNewUser)
1907 					{
1908                   if (gDaemon.ignoreType(Daemon::IgnoreNewUsers))
1909                   {
1910                   gDaemon.rejectEvent(userId, e);
1911                   break;
1912                 }
1913 						bNewUser = false;
1914 					}
1915 
1916                 if (!gDaemon.addUserEvent(*u, e))
1917                   break;
1918                 gOnEventManager.performOnEvent(OnEventData::OnEventChat, *u);
1919                 break;
1920               }
1921 				case ICQ_CMDxSUB_URL:
1922 				{
1923               gLog.info(tr("URL from %s (%s)."), u->getAlias().c_str(), userId.toString().c_str());
1924                 Licq::EventUrl* e = parseUrlEvent(icbmMessage, Licq::EventUrl::TimeNow, nMask, u->userEncoding());
1925 					if (e == NULL)
1926 					{
1927                                           packet.log(Log::Warning, tr("Invalid URL message"));
1928                                           errorOccured = true;
1929                                           break;
1930 					}
1931 
1932 					if (bNewUser)
1933 					{
1934                   if (gDaemon.ignoreType(Daemon::IgnoreNewUsers))
1935                   {
1936                   gDaemon.rejectEvent(userId, e);
1937                   break;
1938                 }
1939 						bNewUser = false;
1940 					}
1941 
1942                 if (!gDaemon.addUserEvent(*u, e))
1943                   break;
1944                 gOnEventManager.performOnEvent(OnEventData::OnEventUrl, *u);
1945                 break;
1946               }
1947 				case ICQ_CMDxSUB_CONTACTxLIST:
1948 				{
1949               gLog.info(tr("Contact list from %s (%s)."),
1950                   u->getAlias().c_str(), userId.toString().c_str());
1951                 Licq::EventContactList* e = parseContactEvent(icbmMessage,
1952                     Licq::EventContactList::TimeNow, nMask, u->userEncoding());
1953 					if (e == NULL)
1954 					{
1955                                           packet.log(Log::Warning, tr("Invalid contact list message"));
1956                                           errorOccured = true;
1957                                           break;
1958 					}
1959 
1960 					if (bNewUser)
1961 					{
1962                   if (gDaemon.ignoreType(Daemon::IgnoreNewUsers))
1963                   {
1964                   gDaemon.rejectEvent(userId, e);
1965                   break;
1966                 }
1967 						bNewUser = false;
1968 					}
1969 
1970                 if (!gDaemon.addUserEvent(*u, e))
1971                   break;
1972                 gOnEventManager.performOnEvent(OnEventData::OnEventMessage, *u);
1973                 break;
1974               }
1975           } // switch nICBMCommand
1976           break;
1977         }
1978 
1979       // Old-style encryption request:
1980       case ICQ_CMDxSUB_SECURExOLD:
1981       {
1982           gLog.info(tr("Received old-style key request from %s (%s) but we do not support it."),
1983               u->getAlias().c_str(), userId.toString().c_str());
1984         // Send the nack back
1985           CPT_AckOldSecureChannel p(theSequence, *u);
1986         AckTCP(p, pSock);
1987         break;
1988       }
1989 
1990       // Secure channel request
1991       case ICQ_CMDxSUB_SECURExOPEN:
1992         {
1993           if (!Licq::gDaemon.haveCryptoSupport())
1994           {
1995             gLog.info(tr("Received secure channel request from %s (%s) but we do not support OpenSSL."),
1996                 u->getAlias().c_str(), userId.toString().c_str());
1997             // Send the nack back
1998             CPT_AckOpenSecureChannel p(theSequence, false, *u);
1999             AckTCP(p, pSock);
2000             break;
2001           }
2002 
2003             if (nInVersion < 6)
2004             {
2005           if (packet.getDataPosRead() + 4 >
2006                               (packet.getDataStart() + packet.getDataSize()))
2007           {
2008             theSequence = (signed short)packet.UnpackUnsignedShort();
2009           }
2010           else
2011             packet >> theSequence;
2012 
2013               packet >> licqChar >> licqVersion;
2014             }
2015 
2016         if (licqChar == 'L')
2017             gLog.info(tr("Secure channel request from %s (%s) [Licq %s]."),
2018                 u->getAlias().c_str(), userId.toString().c_str(),
2019                 Licq::UserEvent::licqVersionToString(licqVersion).c_str());
2020           else
2021             gLog.info(tr("Secure channel request from %s (%s)."),
2022                 u->getAlias().c_str(), userId.toString().c_str());
2023 
2024           CPT_AckOpenSecureChannel p(theSequence, true, *u);
2025         AckTCP(p, pSock);
2026 
2027         if (!pSock->SecureListen())
2028         {
2029           errorOccured = true;
2030           break;
2031         }
2032         u->SetSecure(true);
2033 
2034         // Add the user to our list if they are new
2035         if (bNewUser)
2036         {
2037           if (gDaemon.ignoreType(Daemon::IgnoreNewUsers))
2038             break;
2039           bNewUser = false;
2040         }
2041 
2042         u->SetSendServer(false);
2043           Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
2044               Licq::PluginSignal::SignalUser,
2045               Licq::PluginSignal::UserSecurity, u->id(), 1));
2046 
2047           gLog.info(tr("Secure channel established with %s (%s)"),
2048               u->getAlias().c_str(), userId.toString().c_str());
2049 
2050         break;
2051       }
2052 
2053 
2054       // Secure channel close request
2055       case ICQ_CMDxSUB_SECURExCLOSE:
2056         {
2057           if (!Licq::gDaemon.haveCryptoSupport())
2058           {
2059             gLog.info(tr("Received secure channel close from %s (%s) but we do not support OpenSSL."),
2060                 u->getAlias().c_str(), userId.toString().c_str());
2061             // Send the nack back
2062             CPT_AckCloseSecureChannel p(theSequence, *u);
2063             AckTCP(p, pSock);
2064             break;
2065           }
2066 
2067             if (nInVersion < 6)
2068             {
2069           if (packet.getDataPosRead() + 4 >
2070                               (packet.getDataStart() + packet.getDataSize()))
2071           {
2072             theSequence = (signed short)packet.UnpackUnsignedShort();
2073           }
2074           else
2075             packet >> theSequence;
2076 
2077               packet >> licqChar >> licqVersion;
2078             }
2079 
2080         if (licqChar == 'L')
2081             gLog.info(tr("Secure channel closed by %s (%s) [Licq %s]."),
2082                 u->getAlias().c_str(), userId.toString().c_str(),
2083                 Licq::UserEvent::licqVersionToString(licqVersion).c_str());
2084           else
2085             gLog.info(tr("Secure channel closed by %s (%s)."),
2086                 u->getAlias().c_str(), userId.toString().c_str());
2087 
2088         // send ack
2089           CPT_AckCloseSecureChannel p(theSequence, *u);
2090         AckTCP(p, pSock);
2091 
2092         pSock->SecureStop();
2093         u->SetSecure(false);
2094           Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
2095               Licq::PluginSignal::SignalUser,
2096               Licq::PluginSignal::UserSecurity, u->id(), 0));
2097           break;
2098       }
2099 
2100         default:
2101           packet.log(Log::Unknown, "Unknown TCP message type (%04x)",
2102                      newCommand);
2103           errorOccured = true;
2104       }
2105       break;
2106     }
2107 
2108   //-----ACK--------------------------------------------------------------------
2109   case ICQ_CMDxTCP_ACK:  // message received packet
2110   {
2111     // If this is not from a user on our list then ignore it
2112     if (bNewUser) break;
2113 
2114       Licq::ExtendedData *pExtendedAck = NULL;
2115 
2116     switch (newCommand)
2117     {
2118       case ICQ_CMDxSUB_MSG:
2119       case ICQ_CMDxTCP_READxNAxMSG:
2120       case ICQ_CMDxTCP_READxDNDxMSG:
2121       case ICQ_CMDxTCP_READxOCCUPIEDxMSG:
2122       case ICQ_CMDxTCP_READxAWAYxMSG:
2123       case ICQ_CMDxTCP_READxFFCxMSG:
2124       case ICQ_CMDxSUB_URL:
2125       case ICQ_CMDxSUB_CONTACTxLIST:
2126             if (nInVersion < 6)
2127             {
2128           if (packet.getDataPosRead() + 4 >
2129                               (packet.getDataStart() + packet.getDataSize()))
2130           {
2131             theSequence = (signed short)packet.UnpackUnsignedShort();
2132           }
2133           else
2134             packet >> theSequence;
2135 
2136               packet >> licqChar >> licqVersion;
2137             }
2138             else
2139           packet >> junkLong >> junkLong;
2140         break;
2141 
2142       case ICQ_CMDxSUB_CHAT:
2143       {
2144         string ul = packet.unpackShortStringLE();
2145         packet >> nPortReversed   // port backwards
2146                >> nPort;    // port to connect to for chat
2147             if (nInVersion < 6)
2148             {
2149           if (packet.getDataPosRead() + 4 >
2150                               (packet.getDataStart() + packet.getDataSize()))
2151           {
2152             theSequence = (signed short)packet.UnpackUnsignedShort();
2153           }
2154           else
2155             packet >> theSequence;
2156 
2157               packet >> licqChar >> licqVersion;
2158             }
2159 
2160         if (nPort == 0) nPort = (nPortReversed >> 8) | ((nPortReversed & 0xFF) << 8);
2161 
2162             pExtendedAck = new Licq::ExtendedData(nPort != 0, nPort,
2163                 gTranslator.toUtf8(message, u->userEncoding()));
2164             break;
2165           }
2166 
2167       case ICQ_CMDxSUB_FILE:
2168       {
2169          /* 50 A5 82 00 03 00 DA 07 00 00 50 A5 82 00 03 00 0A 00 6E 6F 20 74 68 61
2170             6E 6B 73 00 D1 EF 04 9F 7F 00 00 01 4A 1F 00 00 04 01 00 00 00 00 00 00
2171             00 01 00 00 00 00 00 00 00 00 00 00 03 00 00 00 */
2172          packet >> nPortReversed
2173                 >> junkShort;
2174          for (int i = 0; i < junkShort; i++) packet >> junkChar;
2175          packet >> junkLong
2176                 >> nPort;
2177             if (nInVersion < 6)
2178             {
2179            if (packet.getDataPosRead() + 4 >
2180                               (packet.getDataStart() + packet.getDataSize()))
2181            {
2182              theSequence = (signed short)packet.UnpackUnsignedShort();
2183            }
2184            else
2185              packet >> theSequence;
2186 
2187               packet >> licqChar >> licqVersion;
2188             }
2189 
2190          // Some clients only send the first port (reversed)
2191          if (nPort == 0) nPort = (nPortReversed >> 8) | ((nPortReversed & 0xFF) << 8);
2192 
2193             pExtendedAck = new Licq::ExtendedData(nPort != 0, nPort,
2194                 gTranslator.toUtf8(message, u->userEncoding()));
2195             break;
2196           }
2197 
2198 		  case ICQ_CMDxSUB_ICBM:
2199 			{
2200 				unsigned short nLen;
2201 				packet >> nLen;
2202 				packet.incDataPosRead(18); // eh?
2203           string plugin = packet.unpackLongStringLE();
2204 
2205           packet.incDataPosRead(nLen - 22 - plugin.size());
2206 				packet.incDataPosRead(4); // left in packet
2207 
2208 				int nICBMCommand = 0;
2209           if (plugin.find("File") != string::npos)
2210 					nICBMCommand = ICQ_CMDxSUB_FILE;
2211           else if (plugin.find("Chat") != string::npos)
2212 					nICBMCommand = ICQ_CMDxSUB_CHAT;
2213           else if (plugin.find("URL") != string::npos)
2214 					nICBMCommand = ICQ_CMDxSUB_URL;
2215           else if (plugin.find("Contacts") != string::npos)
2216 					nICBMCommand = ICQ_CMDxSUB_CONTACTxLIST;
2217           else
2218           {
2219             gLog.info(tr("Unknown direct ack ICBM plugin type: %s"), plugin.c_str());
2220 
2221             if (bNewUser)
2222             {
2223               u.unlock();
2224               Licq::gUserManager.removeLocalUser(userId);
2225             }
2226 					return true;
2227 				}
2228 
2229           string msg = packet.unpackLongStringLE();
2230 
2231 				switch (nICBMCommand)
2232 				{
2233 				case ICQ_CMDxSUB_FILE:
2234 				{
2235 					nPort = packet.UnpackUnsignedShortBE();
2236 					packet.incDataPosRead(2); // unknown
2237 					packet >> nLen; // filename len, including NULL
2238 					packet.incDataPosRead(nLen); // filename
2239 					packet.incDataPosRead(4); // file size
2240 					packet >> nPortReversed;
2241 
2242 					if (nPort == 0)
2243 						nPort = nPortReversed;
2244 
2245                 pExtendedAck = new Licq::ExtendedData(nPort != 0, nPort,
2246                     gTranslator.toUtf8((!message.empty() ? message : msg), u->userEncoding()));
2247                 break;
2248               }
2249 				case ICQ_CMDxSUB_CHAT:
2250 				{
2251                 string ul = packet.unpackShortStringLE();
2252 					nPort = packet.UnpackUnsignedShortBE();
2253 					packet >> nPortReversed;
2254 
2255 					if (nPort == 0)
2256 						nPort = nPortReversed;
2257 
2258           /* this is silly, but appearantly the only way to tell if chat is
2259              accepted (multiparty chat is accepted if port is 0, and rejected
2260              otherwise, normal chat is accepted if the port is given and
2261              rejected if it's 0) */
2262           bool bAccepted = (nPort != 0 && ul[0] == '\0') ||
2263                            (nPort == 0 && ul[0] != '\0');
2264                 pExtendedAck = new Licq::ExtendedData(bAccepted, nPort,
2265                     gTranslator.toUtf8((!message.empty() ? message : msg), u->userEncoding()));
2266                 break;
2267               }
2268             } // switch nICBMCommand
2269 
2270             break;
2271           }
2272 
2273         case ICQ_CMDxSUB_SECURExOPEN:
2274         {
2275           if (!Licq::gDaemon.haveCryptoSupport())
2276           {
2277             errorOccured = true;
2278             break;
2279           }
2280 
2281             if (nInVersion < 6)
2282             {
2283           if (packet.getDataPosRead() + 4 >
2284                               (packet.getDataStart() + packet.getDataSize()))
2285           {
2286             theSequence = (signed short)packet.UnpackUnsignedShort();
2287           }
2288           else
2289             packet >> theSequence;
2290 
2291               packet >> licqChar >> licqVersion;
2292             }
2293 
2294         char l[32] = "";
2295           if (licqChar == 'L')
2296             sprintf(l, " [Licq %s]", Licq::UserEvent::licqVersionToString(licqVersion).c_str());
2297           gLog.info(tr("Secure channel response from %s (%s)%s."),
2298               u->getAlias().c_str(), userId.toString().c_str(), l);
2299 
2300           Licq::Event* e = NULL;
2301 
2302           // Check if the response is ok
2303           if (message.empty())
2304           {
2305             gLog.info(tr("%s (%s) does not support OpenSSL."),
2306                 u->getAlias().c_str(), userId.toString().c_str());
2307           u->SetSecure(false);
2308             Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
2309                 Licq::PluginSignal::SignalUser,
2310                 Licq::PluginSignal::UserSecurity, u->id(), 0));
2311           // find the event, fail it
2312             e = DoneEvent(sockfd, theSequence, Licq::Event::ResultFailed);
2313           }
2314         else
2315         {
2316           // Find the event, succeed it
2317             e = DoneEvent(sockfd, theSequence, Licq::Event::ResultSuccess);
2318 
2319           // Check that a request was in progress...should always be ok
2320           if (e == NULL)
2321           {
2322               gLog.warning(tr("Secure channel response from %s (%s) when no request in progress."),
2323                   u->getAlias().c_str(), userId.toString().c_str());
2324             // Close the connection as we are in trouble
2325             u->SetSecure(false);
2326               u.unlock();
2327               if (bNewUser)
2328                 Licq::gUserManager.removeLocalUser(userId);
2329               Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
2330                   Licq::PluginSignal::SignalUser,
2331                   Licq::PluginSignal::UserSecurity, userId, 0));
2332             return false;
2333           }
2334 
2335           if (!pSock->SecureConnect())
2336           {
2337             errorOccured = true;
2338               e->m_eResult = Licq::Event::ResultFailed;
2339             }
2340           else
2341           {
2342               gLog.info(tr("Secure channel established with %s (%s)"),
2343                   u->getAlias().c_str(), userId.toString().c_str());
2344             u->SetSecure(true);
2345               Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
2346                   Licq::PluginSignal::SignalUser,
2347                   Licq::PluginSignal::UserSecurity, u->id(), 1));
2348             }
2349           }
2350 
2351           // finish up
2352           e->mySubResult = Licq::Event::SubResultAccept;
2353           u.unlock();
2354           if (bNewUser)
2355             Licq::gUserManager.removeLocalUser(userId);
2356         ProcessDoneEvent(e);
2357 
2358         // get out of here now as we don't want standard ack processing
2359         return !errorOccured;
2360       }
2361 
2362 
2363       case ICQ_CMDxSUB_SECURExCLOSE:
2364         {
2365           if (!Licq::gDaemon.haveCryptoSupport())
2366           {
2367             errorOccured = true;
2368             break;
2369           }
2370             if (nInVersion < 6)
2371             {
2372           if (packet.getDataPosRead() + 4 >
2373                               (packet.getDataStart() + packet.getDataSize()))
2374           {
2375             theSequence = (signed short)packet.UnpackUnsignedShort();
2376           }
2377           else
2378             packet >> theSequence;
2379 
2380               packet >> licqChar >> licqVersion;
2381             }
2382 
2383         char l[32] = "";
2384           if (licqChar == 'L')
2385             sprintf(l, " [Licq %s]", Licq::UserEvent::licqVersionToString(licqVersion).c_str());
2386           gLog.info(tr("Secure channel with %s (%s) closed %s."),
2387               u->getAlias().c_str(), userId.toString().c_str(), l);
2388 
2389         // Find the event, succeed it
2390           Licq::Event* e = DoneEvent(sockfd, theSequence, Licq::Event::ResultSuccess);
2391 
2392         // Check that a request was in progress...should always be ok
2393         if (e == NULL)
2394         {
2395           // Close the connection as we are in trouble
2396             if (bNewUser)
2397             {
2398               u.unlock();
2399               Licq::gUserManager.removeLocalUser(userId);
2400             }
2401           delete e;
2402           return false;
2403         }
2404 
2405         pSock->SecureStop();
2406         u->SetSecure(false);
2407           Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
2408               Licq::PluginSignal::SignalUser,
2409               Licq::PluginSignal::UserSecurity, u->id(), 0));
2410 
2411           u.unlock();
2412           if (bNewUser)
2413             Licq::gUserManager.removeLocalUser(userId);
2414 
2415           // finish up
2416           e->mySubResult = Licq::Event::SubResultAccept;
2417         ProcessDoneEvent(e);
2418 
2419         // get out of here now as we don't want standard ack processing
2420         return true;
2421       }
2422 
2423         default:
2424           packet.log(Log::Unknown, "Unknown TCP Ack subcommand (%04x)",
2425                      newCommand);
2426           errorOccured = true;
2427       }
2428 
2429     char l[32] = "";
2430       if (licqChar == 'L')
2431         sprintf(l, " [Licq %s]", Licq::UserEvent::licqVersionToString(licqVersion).c_str());
2432 
2433     // output the away message if there is one (ie if user status is not online)
2434       unsigned subResult;
2435     if (ackFlags == ICQ_TCPxACK_REFUSE)
2436     {
2437       gLog.info(tr("Refusal from %s (#%d)%s."), u->getAlias().c_str(), -theSequence, l);
2438         subResult = Licq::Event::SubResultRefuse;
2439       }
2440       else
2441       {
2442       // Update the away message if it's changed
2443         string awayMsg = gTranslator.toUtf8(message, u->userEncoding());
2444         if (u->autoResponse() != awayMsg)
2445         {
2446           u->setAutoResponse(awayMsg);
2447           u->SetShowAwayMsg(!awayMsg.empty());
2448         gLog.info(tr("Auto response from %s (#%d)%s."), u->getAlias().c_str(), -theSequence, l);
2449       }
2450 
2451       switch(ackFlags)
2452       {
2453         case ICQ_TCPxACK_ONLINE:
2454           gLog.info(tr("Ack from %s (#%d)%s."), u->getAlias().c_str(), -theSequence, l);
2455             if (pExtendedAck && !pExtendedAck->accepted())
2456               subResult = Licq::Event::SubResultReturn;
2457             else
2458               subResult = Licq::Event::SubResultAccept;
2459             break;
2460         case ICQ_TCPxACK_AWAY:
2461         case ICQ_TCPxACK_NA:
2462         case ICQ_TCPxACK_OCCUPIEDx2: //auto decline due to occupied mode
2463           gLog.info(tr("Ack from %s (#%d)%s."), u->getAlias().c_str(), -theSequence, l);
2464             subResult = Licq::Event::SubResultRefuse;
2465             break;
2466         case ICQ_TCPxACK_OCCUPIED:
2467         case ICQ_TCPxACK_DND:
2468           gLog.info(tr("Returned from %s (#%d)%s."), u->getAlias().c_str(), -theSequence, l);
2469             subResult = Licq::Event::SubResultReturn;
2470             break;
2471         case ICQ_TCPxACK_OCCUPIEDxCAR:
2472         case ICQ_TCPxACK_DNDxCAR:
2473           gLog.info(tr("Custom %s response from %s (#%d)%s."),
2474               (ackFlags == ICQ_TCPxACK_DNDxCAR ? tr("DnD") : tr("Occupied")),
2475               u->getAlias().c_str(), -theSequence, l);
2476             subResult = Licq::Event::SubResultAccept; // FIXME: or should this be ACK_RETURN ?
2477             break;
2478           default:
2479           gLog.unknown(tr("Unknown ack flag from %s (#%d): %04x %s"),
2480               u->getAlias().c_str(), -theSequence, ackFlags, l);
2481             subResult = Licq::Event::SubResultAccept;
2482       }
2483     }
2484 
2485       Licq::Event *e = DoneEvent(sockfd, theSequence, Licq::Event::ResultAcked);
2486     if (e != NULL)
2487     {
2488       e->m_pExtendedAck = pExtendedAck;
2489         e->mySubResult = subResult;
2490 
2491         u.unlock();
2492         if (bNewUser)
2493           Licq::gUserManager.removeLocalUser(userId);
2494 
2495       ProcessDoneEvent(e);
2496       return true;
2497     }
2498     else
2499     {
2500       gLog.warning(tr("Ack for unknown event."));
2501       errorOccured = true;
2502       delete pExtendedAck;
2503     }
2504     break;
2505   }
2506 
2507   //-----CANCEL-----------------------------------------------------------------
2508   case ICQ_CMDxTCP_CANCEL:
2509     // If from a new user, ignore it
2510     if (bNewUser) break;
2511 
2512     switch (newCommand)
2513     {
2514       case ICQ_CMDxSUB_CHAT:
2515       {
2516           gLog.info(tr("Chat request from %s (%s) cancelled."),
2517               u->getAlias().c_str(), userId.toString().c_str());
2518             if (nInVersion < 6)
2519             {
2520           packet >> junkLong >> junkLong >> junkShort >> junkChar;
2521           if (packet.getDataPosRead() + 4 >
2522                               (packet.getDataStart() + packet.getDataSize()))
2523           {
2524             theSequence = (signed short)packet.UnpackUnsignedShort();
2525           }
2526           else
2527             packet >> theSequence;
2528         }
2529 
2530         for (unsigned short i = 0; i < u->NewMessages(); i++)
2531         {
2532           if (u->EventPeek(i)->Sequence() == theSequence)
2533           {
2534             u->CancelEvent(i);
2535             break;
2536           }
2537         }
2538         break;
2539       }
2540       case ICQ_CMDxSUB_FILE:
2541       {
2542           gLog.info(tr("File transfer request from %s (%s) cancelled."),
2543               u->getAlias().c_str(), userId.toString().c_str());
2544             if (nInVersion < 6)
2545             {
2546           packet >> junkLong >> junkShort >> junkChar >> junkLong >> junkLong;
2547           if (packet.getDataPosRead() + 4 >
2548                               (packet.getDataStart() + packet.getDataSize()))
2549           {
2550             theSequence = (signed short)packet.UnpackUnsignedShort();
2551           }
2552           else
2553             packet >> theSequence;
2554         }
2555 
2556         for (unsigned short i = 0; i < u->NewMessages(); i++)
2557         {
2558           if (u->EventPeek(i)->Sequence() == theSequence)
2559           {
2560             u->CancelEvent(i);
2561             break;
2562           }
2563         }
2564         break;
2565       }
2566 
2567       default:
2568          break;
2569     }
2570 
2571     break;
2572 
2573     default:
2574       packet.log(Log::Unknown, "Unknown TCP packet (command 0x%04x)",
2575                  command);
2576       errorOccured = true;
2577       break;
2578   }
2579 
2580   }
2581   if (bNewUser)
2582   {
2583     u.unlock();
2584     Licq::gUserManager.removeLocalUser(userId);
2585     return false;
2586   }
2587   return !errorOccured;
2588 }
2589 
processPluginMessage(CBuffer & packet,User * u,int channel,bool bIsAck,unsigned long nMsgID1,unsigned long nMsgID2,unsigned short nSequence,Licq::TCPSocket * pSock)2590 bool IcqProtocol::processPluginMessage(CBuffer &packet, User* u,
2591     int channel,
2592                                       bool bIsAck,
2593                                       unsigned long nMsgID1,
2594                                       unsigned long nMsgID2,
2595                                       unsigned short nSequence,
2596     Licq::TCPSocket* pSock)
2597 {
2598   bool errorOccured = false;
2599 
2600   switch (channel)
2601   {
2602     case DcSocket::ChannelInfo:
2603     {
2604     packet.incDataPosRead(2);
2605     char error_level = packet.UnpackChar();
2606 
2607     if (!bIsAck)
2608     {
2609       if (error_level != ICQ_PLUGIN_REQUEST)
2610       {
2611           gLog.warning(tr("Info plugin request with unknown level %u from %s."),
2612               error_level, u->getAlias().c_str());
2613         errorOccured = true;
2614         break;
2615       }
2616       char GUID[GUID_LENGTH];
2617       for (int i = 0 ; i < GUID_LENGTH; i ++)
2618         packet >> GUID[i];
2619 
2620       if (memcmp(GUID, PLUGIN_QUERYxINFO, GUID_LENGTH) == 0)
2621       {
2622           gLog.info(tr("Info plugin list request from %s."), u->getAlias().c_str());
2623         if (pSock)
2624         {
2625           CPT_InfoPluginListResp p(u, nSequence);
2626           AckTCP(p, pSock);
2627         }
2628         else
2629         {
2630           CPU_InfoPluginListResp *p = new CPU_InfoPluginListResp(u, nMsgID1,
2631                                                     nMsgID2, nSequence);
2632           SendEvent_Server(p);
2633         }
2634       }
2635       else if (memcmp(GUID, PLUGIN_PHONExBOOK, GUID_LENGTH) == 0)
2636       {
2637           gLog.info(tr("Phone Book request from %s."), u->getAlias().c_str());
2638         if (pSock)
2639         {
2640           CPT_InfoPhoneBookResp p(u, nSequence);
2641           AckTCP(p, pSock);
2642         }
2643         else
2644         {
2645           CPU_InfoPhoneBookResp *p = new CPU_InfoPhoneBookResp(u, nMsgID1,
2646                                                        nMsgID2, nSequence);
2647           SendEvent_Server(p);
2648         }
2649       }
2650       else if (memcmp(GUID, PLUGIN_PICTURE, GUID_LENGTH) == 0)
2651       {
2652           gLog.info(tr("Picture request from %s."), u->getAlias().c_str());
2653 
2654         if (pSock)
2655         {
2656           CPT_InfoPictureResp p(u, nSequence);
2657           AckTCP(p, pSock);
2658         }
2659         else
2660         {
2661           CPU_InfoPictureResp *p = new CPU_InfoPictureResp(u, nMsgID1, nMsgID2,
2662                                                                 nSequence);
2663           SendEvent_Server(p);
2664         }
2665       }
2666       else
2667       {
2668           gLog.warning(tr("Unknown info request from %s."), u->getAlias().c_str());
2669         if (pSock)
2670         {
2671             CPT_PluginError p(u, nSequence, DcSocket::ChannelInfo);
2672           AckTCP(p, pSock);
2673         }
2674         else
2675         {
2676           CPU_PluginError *p = new CPU_PluginError(u, nMsgID1, nMsgID2, nSequence,
2677                                                    PLUGIN_INFOxMANAGER);
2678           SendEvent_Server(p);
2679         }
2680         errorOccured = true;
2681       }
2682     }
2683     else
2684     {
2685         Licq::Event::ResultType result;
2686 
2687       switch (error_level)
2688       {
2689       case ICQ_PLUGIN_SUCCESS:
2690       {
2691         packet.incDataPosRead(4); //Unknown
2692         //Time of last update
2693         unsigned long nTime = packet.UnpackUnsignedLong();
2694         if (nTime == u->ClientInfoTimestamp())
2695           u->SetOurClientInfoTimestamp(nTime);
2696 
2697         //bytes remaining in packet
2698         unsigned long len = packet.UnpackUnsignedLong();
2699         if (len < 8)
2700         {
2701           //this could be no plugins or no picture, need to check
2702               Licq::Event* e = pSock ? DoneEvent(pSock->Descriptor(), nSequence,
2703                       Licq::Event::ResultAcked) :
2704               DoneServerEvent(nMsgID2, Licq::Event::ResultAcked);
2705 
2706           if (e == NULL)
2707           {
2708                 gLog.warning(tr("Ack for unknown event from %s."), u->getAlias().c_str());
2709                 return true;
2710               }
2711 
2712           const char *GUID;
2713               CPacketTcp* packetTcp = dynamic_cast<CPacketTcp*>(e->m_pPacket);
2714           if (e->SNAC() ==
2715                     MAKESNAC(ICQ_SNACxFAM_MESSAGE, ICQ_SNACxMSG_SENDxSERVER) &&
2716               e->ExtraInfo() == ServerInfoPluginRequest)
2717           {
2718             GUID = ((CPU_InfoPluginReq *)e->m_pPacket)->RequestGUID();
2719               }
2720               else if (packetTcp != NULL && packetTcp->channel() == DcSocket::ChannelInfo &&
2721                    e->ExtraInfo() == DirectInfoPluginRequest)
2722           {
2723             GUID = ((CPT_InfoPluginReq *)e->m_pPacket)->RequestGUID();
2724           }
2725           else
2726           {
2727                 gLog.warning(tr("Ack for the wrong event from %s."), u->getAlias().c_str());
2728                 delete e;
2729                 return true;
2730               }
2731 
2732           if (memcmp(GUID, PLUGIN_PICTURE, GUID_LENGTH) == 0)
2733           {
2734                 gLog.info(tr("%s has no picture."), u->getAlias().c_str());
2735 
2736                 if (remove(u->pictureFileName().c_str()) != 0 && errno != ENOENT)
2737                 {
2738                   gLog.error(tr("Unable to delete %s's picture file (%s): %s."),
2739                       u->getAlias().c_str(), u->pictureFileName().c_str(), strerror(errno));
2740                 }
2741 
2742             u->SetEnableSave(false);
2743             u->SetPicturePresent(false);
2744             u->SetEnableSave(true);
2745               u->save(Licq::User::SavePictureInfo);
2746 
2747               Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
2748                   Licq::PluginSignal::SignalUser,
2749                   Licq::PluginSignal::UserPicture, u->id()));
2750             }
2751           else if (memcmp(GUID, PLUGIN_QUERYxINFO, GUID_LENGTH) == 0)
2752           {
2753                 gLog.info(tr("%s has no info plugins."), u->getAlias().c_str());
2754               }
2755               else
2756               {
2757                 gLog.unknown(tr("Unknown info response with no data from %s."), u->getAlias().c_str());
2758               }
2759 
2760           ProcessDoneEvent(e);
2761           return false;
2762         }
2763         else
2764         {
2765           unsigned long nRequest = packet.UnpackUnsignedLong();
2766           unsigned long nEntries = packet.UnpackUnsignedLong();
2767           switch (nRequest)
2768           {
2769           case ICQ_PLUGIN_RESP_INFOxLIST:
2770           case ICQ_PLUGIN_RESP_INFOxLISTx0:
2771           {
2772             for (; nEntries > 0; nEntries --)
2773             {
2774               packet.incDataPosRead(GUID_LENGTH); // GUID of plugin
2775               packet.incDataPosRead(4); //Unknown
2776                     string name = packet.unpackLongStringLE();
2777                     string fullName = packet.unpackLongStringLE();
2778 
2779               packet.incDataPosRead(4); //Unknown (always 0?)
2780 
2781                     gLog.info(tr("%s has %s (%s)."), u->getAlias().c_str(), name.c_str(), fullName.c_str());
2782                   }
2783                   break;
2784                 }
2785 
2786                 case ICQ_PLUGIN_RESP_PHONExBOOK:
2787                 {
2788                   gLog.info(tr("Phone Book reply from %s."), u->getAlias().c_str());
2789                   struct Licq::PhoneBookEntry* pb = new Licq::PhoneBookEntry[nEntries];
2790                   char* buf;
2791             for (unsigned long i = 0; i < nEntries; i ++)
2792             {
2793               unsigned long nLen = packet.UnpackUnsignedLong();
2794                     buf = new char[nLen + 1];
2795               for (unsigned long j = 0; j < nLen; j++)
2796                       packet >> buf[j];
2797                     buf[nLen] = '\0';
2798                     pb[i].description = buf;
2799                     delete[] buf;
2800 
2801               nLen = packet.UnpackUnsignedLong();
2802                     buf = new char[nLen + 1];
2803               for (unsigned long j = 0; j < nLen; j++)
2804                       packet >> buf[j];
2805                     buf[nLen] = '\0';
2806                     pb[i].areaCode = buf;
2807                     delete[] buf;
2808 
2809               nLen = packet.UnpackUnsignedLong();
2810                     buf = new char[nLen + 1];
2811               for (unsigned long j = 0; j < nLen; j++)
2812                       packet >> buf[j];
2813                     buf[nLen] = '\0';
2814                     pb[i].phoneNumber = buf;
2815                     delete[] buf;
2816 
2817               nLen = packet.UnpackUnsignedLong();
2818                     buf = new char[nLen + 1];
2819               for (unsigned long j = 0; j < nLen; j++)
2820                       packet >> buf[j];
2821                     buf[nLen] = '\0';
2822                     pb[i].extension = buf;
2823                     delete[] buf;
2824 
2825               nLen = packet.UnpackUnsignedLong();
2826                     buf = new char[nLen + 1];
2827               for (unsigned long j = 0; j < nLen; j++)
2828                       packet >> buf[j];
2829                     buf[nLen] = '\0';
2830                     pb[i].country = buf;
2831                     delete[] buf;
2832 
2833               pb[i].nActive = packet.UnpackUnsignedLong();
2834             }
2835             for (unsigned long i = 0; i < nEntries; i ++)
2836             {
2837               packet.UnpackUnsignedLong(); // entry length
2838 
2839               pb[i].nType = packet.UnpackUnsignedLong();
2840 
2841               unsigned long nLen = packet.UnpackUnsignedLong();
2842                     buf = new char[nLen + 1];
2843               for (unsigned long j = 0; j < nLen; j++)
2844                       packet >> buf[j];
2845                     buf[nLen] = '\0';
2846                     pb[i].gateway = buf;
2847                     delete[] buf;
2848 
2849               pb[i].nGatewayType = packet.UnpackUnsignedLong();
2850               pb[i].nSmsAvailable = packet.UnpackUnsignedLong();
2851               pb[i].nRemoveLeading0s = packet.UnpackUnsignedLong();
2852               pb[i].nPublish = packet.UnpackUnsignedLong();
2853             }
2854 
2855             u->SetEnableSave(false);
2856                 u->getPhoneBook().clear();
2857             for (unsigned long i = 0; i < nEntries; i++)
2858             {
2859                   u->getPhoneBook().push_back(pb[i]);
2860                 }
2861             u->SetEnableSave(true);
2862                 u->save(User::SaveUserInfo);
2863                   delete [] pb;
2864 
2865                 Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
2866                     Licq::PluginSignal::SignalUser,
2867                     Licq::PluginSignal::UserInfo, u->id()));
2868                 break;
2869               }
2870 
2871                 case ICQ_PLUGIN_RESP_PICTURE:
2872                 {
2873                   gLog.info(tr("Picture reply from %s."), u->getAlias().c_str());
2874             packet.incDataPosRead(nEntries); // filename, don't care
2875             unsigned long nLen = packet.UnpackUnsignedLong();
2876             if (nLen == 0)	// do not create empty .pic files
2877               break;
2878 
2879                   int nFD = open(u->pictureFileName().c_str(), O_WRONLY | O_CREAT | O_TRUNC, 00664);
2880             if (nFD == -1)
2881             {
2882                     gLog.error(tr("Unable to open picture file (%s): %s."),
2883                         u->pictureFileName().c_str(), strerror(errno));
2884                     break;
2885                   }
2886 
2887                   string data = packet.unpackRawString(nLen);
2888                   write(nFD, data.c_str(), nLen);
2889             close(nFD);
2890 
2891             u->SetEnableSave(false);
2892             u->SetPicturePresent(true);
2893             u->SetEnableSave(true);
2894                 u->save(Licq::User::SavePictureInfo);
2895 
2896                 Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
2897                     Licq::PluginSignal::SignalUser,
2898                     Licq::PluginSignal::UserPicture, u->id()));
2899                 break;
2900               }
2901             }
2902           }
2903 
2904             result = Licq::Event::ResultAcked;
2905             break;
2906       }
2907       case ICQ_PLUGIN_ERROR:
2908       {
2909             gLog.warning(tr("Info plugin not available from %s."), u->getAlias().c_str());
2910             result = Licq::Event::ResultError;
2911             break;
2912           }
2913           case ICQ_PLUGIN_REJECTED:
2914           {
2915             gLog.info(tr("%s refused our request."), u->getAlias().c_str());
2916             result = Licq::Event::ResultFailed;
2917             break;
2918           }
2919           case ICQ_PLUGIN_AWAY:
2920           {
2921             gLog.info(tr("Our request was refused because %s is away."), u->getAlias().c_str());
2922             result = Licq::Event::ResultFailed;
2923             break;
2924           }
2925           default:
2926           {
2927             gLog.warning(tr("Unknown reply level %u from %s"),
2928                 error_level, u->getAlias().c_str());
2929         errorOccured = true;
2930             result = Licq::Event::ResultError;
2931             break;
2932           }
2933         }
2934 
2935         Licq::Event* e = pSock ? DoneEvent(pSock->Descriptor(), nSequence,
2936                                       result) :
2937                             DoneServerEvent(nMsgID2, result);
2938       if (e == NULL)
2939           gLog.warning(tr("Ack for unknown event from %s."), u->getAlias().c_str());
2940       else
2941         ProcessDoneEvent(e);
2942 
2943     }
2944 
2945       break;
2946     }
2947     case DcSocket::ChannelStatus:
2948     {
2949     packet.incDataPosRead(2);
2950     char error_level = packet.UnpackChar();
2951 
2952     if (!bIsAck)
2953     {
2954       if (error_level != ICQ_PLUGIN_REQUEST)
2955       {
2956           gLog.warning(tr("Unknown status plugin request level %u from %s."),
2957               error_level, u->getAlias().c_str());
2958         errorOccured = true;
2959         break;
2960       }
2961 
2962       char GUID[GUID_LENGTH];
2963       for (int i = 0 ; i < GUID_LENGTH; i ++)
2964         packet >> GUID[i];
2965 
2966       if (memcmp(GUID, PLUGIN_QUERYxSTATUS, GUID_LENGTH) == 0)
2967       {
2968           gLog.info(tr("Status plugin list request from %s."), u->getAlias().c_str());
2969         if (pSock)
2970         {
2971           CPT_StatusPluginListResp p(u, nSequence);
2972           AckTCP(p, pSock);
2973         }
2974         else
2975         {
2976           CPU_StatusPluginListResp *p = new CPU_StatusPluginListResp(u, nMsgID1,
2977                                                         nMsgID2, nSequence);
2978           SendEvent_Server(p);
2979         }
2980       }
2981       else if (memcmp(GUID, PLUGIN_FILExSERVER, GUID_LENGTH) == 0)
2982       {
2983           gLog.info(tr("File server status request from %s."), u->getAlias().c_str());
2984         unsigned long nStatus;
2985         {
2986           OwnerReadGuard o(myOwnerId);
2987           switch (o->sharedFilesStatus())
2988           {
2989             case IcqPluginActive: nStatus = ICQ_PLUGIN_STATUSxACTIVE; break;
2990             case IcqPluginBusy: nStatus = ICQ_PLUGIN_STATUSxBUSY; break;
2991             default: nStatus = ICQ_PLUGIN_STATUSxINACTIVE; break;
2992           }
2993         }
2994         if (pSock)
2995         {
2996           CPT_StatusPluginResp p(u, nSequence, nStatus);
2997           AckTCP(p, pSock);
2998         }
2999         else
3000         {
3001           CPU_StatusPluginResp *p = new CPU_StatusPluginResp(u, nMsgID1, nMsgID2,
3002                                            nSequence, nStatus);
3003           SendEvent_Server(p);
3004         }
3005       }
3006       else if (memcmp(GUID, PLUGIN_ICQxPHONE, GUID_LENGTH) == 0)
3007       {
3008           gLog.info(tr("ICQphone status request from %s."), u->getAlias().c_str());
3009         unsigned long nStatus;
3010         {
3011           OwnerReadGuard o(myOwnerId);
3012           switch (o->icqPhoneStatus())
3013           {
3014             case IcqPluginActive: nStatus = ICQ_PLUGIN_STATUSxACTIVE; break;
3015             case IcqPluginBusy: nStatus = ICQ_PLUGIN_STATUSxBUSY; break;
3016             default: nStatus = ICQ_PLUGIN_STATUSxINACTIVE; break;
3017           }
3018         }
3019         if (pSock)
3020         {
3021           CPT_StatusPluginResp p(u, nSequence, nStatus);
3022           AckTCP(p, pSock);
3023         }
3024         else
3025         {
3026           CPU_StatusPluginResp *p = new CPU_StatusPluginResp(u, nMsgID1, nMsgID2,
3027                                            nSequence, nStatus);
3028           SendEvent_Server(p);
3029         }
3030       }
3031       else if (memcmp(GUID, PLUGIN_FOLLOWxME, GUID_LENGTH) == 0)
3032       {
3033           gLog.info(tr("Phone \"Follow Me\" status request from %s."), u->getAlias().c_str());
3034         unsigned long nStatus;
3035         {
3036           OwnerReadGuard o(myOwnerId);
3037           switch (o->phoneFollowMeStatus())
3038           {
3039             case IcqPluginActive: nStatus = ICQ_PLUGIN_STATUSxACTIVE; break;
3040             case IcqPluginBusy: nStatus = ICQ_PLUGIN_STATUSxBUSY; break;
3041             default: nStatus = ICQ_PLUGIN_STATUSxINACTIVE; break;
3042           }
3043         }
3044         if (pSock)
3045         {
3046           CPT_StatusPluginResp p(u, nSequence, nStatus);
3047           AckTCP(p, pSock);
3048         }
3049         else
3050         {
3051           CPU_StatusPluginResp *p = new CPU_StatusPluginResp(u, nMsgID1, nMsgID2,
3052                                            nSequence, nStatus);
3053           SendEvent_Server(p);
3054         }
3055       }
3056       else
3057       {
3058           gLog.warning(tr("Unknown status request from %s."), u->getAlias().c_str());
3059         if (pSock)
3060         {
3061             CPT_PluginError p(u, nSequence, DcSocket::ChannelStatus);
3062           AckTCP(p, pSock);
3063         }
3064         else
3065         {
3066           CPU_PluginError *p = new CPU_PluginError(u, nMsgID1, nMsgID2, nSequence,
3067                                                    PLUGIN_STATUSxMANAGER);
3068           SendEvent_Server(p);
3069         }
3070         errorOccured = true;
3071       }
3072     }
3073     else
3074     {
3075         Licq::Event::ResultType result;
3076 
3077       switch (error_level)
3078       {
3079       case ICQ_PLUGIN_SUCCESS:
3080       {
3081         packet.incDataPosRead(13); //Unknown
3082         //Time of last installation of new status plugins
3083         unsigned long nTime = packet.UnpackUnsignedLong();
3084         if (nTime == u->ClientStatusTimestamp())
3085           u->SetOurClientStatusTimestamp(nTime);
3086 
3087         //bytes remaining in packet
3088         unsigned long len = packet.UnpackUnsignedLong();
3089         if (len < 8)
3090         {
3091               gLog.info(tr("%s has no status plugins.\n"), u->getAlias().c_str());
3092             }
3093             else
3094             {
3095           packet.incDataPosRead(4); // Unknown
3096           unsigned long nEntries = packet.UnpackUnsignedLong();
3097           for (; nEntries > 0; nEntries --)
3098           {
3099             packet.incDataPosRead(GUID_LENGTH); // GUID of plugin
3100             packet.incDataPosRead(4); //Unknown
3101                 string name = packet.unpackLongStringLE();
3102                 string fullName = packet.unpackLongStringLE();
3103 
3104             packet.incDataPosRead(4); //Unknown (always 0?)
3105 
3106                 gLog.info(tr("%s has %s (%s)."), u->getAlias().c_str(), name.c_str(), fullName.c_str());
3107               }
3108             }
3109 
3110             result = Licq::Event::ResultAcked;
3111             break;
3112       }
3113       case ICQ_PLUGIN_STATUSxREPLY:
3114       {
3115             Licq::Event* e = pSock ? DoneEvent(pSock->Descriptor(), nSequence,
3116                     Licq::Event::ResultAcked) :
3117                 DoneServerEvent(nMsgID2, Licq::Event::ResultAcked);
3118 
3119         if (e == NULL)
3120         {
3121               gLog.warning(tr("Ack for unknown event from %s."), u->getAlias().c_str());
3122               return true;
3123             }
3124 
3125         const char *GUID;
3126             CPacketTcp* packetTcp = dynamic_cast<CPacketTcp*>(e->m_pPacket);
3127         if (e->SNAC() ==
3128                   MAKESNAC(ICQ_SNACxFAM_MESSAGE, ICQ_SNACxMSG_SENDxSERVER) &&
3129             e->ExtraInfo() == ServerStatusPluginRequest)
3130         {
3131           GUID = ((CPU_StatusPluginReq *)e->m_pPacket)->RequestGUID();
3132             }
3133             else if (packetTcp != NULL && packetTcp->channel() == DcSocket::ChannelInfo &&
3134                  e->ExtraInfo() == DirectStatusPluginRequest)
3135         {
3136           GUID = ((CPT_StatusPluginReq *)e->m_pPacket)->RequestGUID();
3137         }
3138         else
3139         {
3140               gLog.warning(tr("Ack for the wrong event from %s."), u->getAlias().c_str());
3141               delete e;
3142               return true;
3143             }
3144 
3145         packet.incDataPosRead(4); // Unknown
3146         unsigned long nState = packet.UnpackUnsignedLong();
3147         unsigned long nTime = packet.UnpackUnsignedLong();
3148 
3149         if (nTime == u->ClientStatusTimestamp())
3150           u->SetOurClientStatusTimestamp(nTime);
3151 
3152         const char* szState;
3153             unsigned pluginState;
3154         switch (nState)
3155         {
3156               case ICQ_PLUGIN_STATUSxINACTIVE:
3157                 szState = "inactive";
3158                 pluginState = IcqPluginInactive;
3159                 break;
3160               case ICQ_PLUGIN_STATUSxACTIVE:
3161                 szState = "active";
3162                 pluginState = IcqPluginActive;
3163                 break;
3164               case ICQ_PLUGIN_STATUSxBUSY:
3165                 szState = "busy";
3166                 pluginState = IcqPluginBusy;
3167                 break;
3168               default:
3169                 szState = "unknown";
3170                 pluginState = IcqPluginInactive;
3171                 break;
3172             }
3173 
3174         if (memcmp(GUID, PLUGIN_FILExSERVER, GUID_LENGTH) == 0)
3175         {
3176               gLog.info(tr("%s's Shared Files Directory is %s."), u->getAlias().c_str(), szState);
3177               u->setSharedFilesStatus(pluginState);
3178             }
3179         else if (memcmp(GUID, PLUGIN_FOLLOWxME, GUID_LENGTH) == 0)
3180         {
3181               gLog.info(tr("%s's Phone \"Follow Me\" is %s."), u->getAlias().c_str(), szState);
3182               u->setPhoneFollowMeStatus(pluginState);
3183             }
3184         else if (memcmp(GUID, PLUGIN_ICQxPHONE, GUID_LENGTH) == 0)
3185         {
3186               gLog.info(tr("%s's ICQphone is %s."), u->getAlias().c_str(), szState);
3187               u->setIcqPhoneStatus(pluginState);
3188             }
3189 
3190         // Which plugin?
3191             Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
3192                 Licq::PluginSignal::SignalUser,
3193                 Licq::PluginSignal::UserPluginStatus, u->id(), 0));
3194 
3195         ProcessDoneEvent(e);
3196         return false;
3197       }
3198       case ICQ_PLUGIN_ERROR:
3199       {
3200             gLog.warning(tr("Status plugin not available from %s."), u->getAlias().c_str());
3201             result = Licq::Event::ResultError;
3202             break;
3203           }
3204           case ICQ_PLUGIN_REJECTED:
3205           {
3206             gLog.info(tr("%s refused our request."), u->getAlias().c_str());
3207             result = Licq::Event::ResultFailed;
3208             break;
3209           }
3210           case ICQ_PLUGIN_AWAY:
3211           {
3212             gLog.info(tr("Our request was refused because %s is away."), u->getAlias().c_str());
3213             result = Licq::Event::ResultFailed;
3214             break;
3215           }
3216           default:
3217           {
3218             gLog.warning(tr("Unknown reply level %u from %s"),
3219                 error_level, u->getAlias().c_str());
3220         errorOccured = true;
3221             result = Licq::Event::ResultError;
3222             break;
3223           }
3224         }
3225 
3226         Licq::Event* e = pSock ? DoneEvent(pSock->Descriptor(), nSequence,
3227                                       result) :
3228                             DoneServerEvent(nMsgID2, result);
3229       if (e == NULL)
3230           gLog.warning(tr("Ack for unknown event from %s."), u->getAlias().c_str());
3231       else
3232         ProcessDoneEvent(e);
3233 
3234     }
3235 
3236     break;
3237   }
3238     default:
3239     {
3240       gLog.warning(tr("Unknown channel %u from %s"), channel, u->getAlias().c_str());
3241     if (!pSock)
3242     {
3243       CPU_NoManager *p = new CPU_NoManager(u, nMsgID1, nMsgID2);
3244       SendEvent_Server(p);
3245     }
3246 
3247     errorOccured = true;
3248     break;
3249   }
3250   }
3251   return errorOccured;
3252 }
3253 
3254 //-----CICQDaemon::AckTCP--------------------------------------------------------------
AckTCP(CPacketTcp & p,int nSd)3255 void IcqProtocol::AckTCP(CPacketTcp &p, int nSd)
3256 {
3257 #if ICQ_VERSION_TCP == 3
3258   Licq::TCPSocket* s = dynamic_cast<Licq::TCPSocket*>(gSocketManager.FetchSocket(nSD));
3259   if (s != NULL)
3260   {
3261     s->Send(p.getBuffer());
3262     gSocketManager.DropSocket(s);
3263   }
3264 #else
3265   SendEvent(nSd, p, false);
3266 #endif
3267 }
3268 
AckTCP(CPacketTcp & p,Licq::TCPSocket * tcp)3269 void IcqProtocol::AckTCP(CPacketTcp &p, Licq::TCPSocket* tcp)
3270 {
3271 #if ICQ_VERSION_TCP == 3
3272   tcp->Send(p.getBuffer());
3273 #else
3274   SendEvent(tcp, p, false);
3275 #endif
3276 }
3277 
Handshake_Recv(DcSocket * s,unsigned short nPort,bool bConfirm,bool bChat)3278 bool IcqProtocol::Handshake_Recv(DcSocket* s, unsigned short nPort, bool bConfirm, bool bChat)
3279 {
3280   char cHandshake;
3281   unsigned short nVersionMajor, nVersionMinor;
3282   CBuffer &b = s->RecvBuffer();
3283   b.unpackUInt16LE(); // Packet length
3284   b >> cHandshake >> nVersionMajor >> nVersionMinor;
3285 
3286   unsigned long nUin = 0;
3287   unsigned short nVersion = 0;
3288   char id[16];
3289   Licq::UserId userId;
3290 
3291   switch (IcqProtocol::dcVersionToUse(nVersionMajor))
3292   {
3293     case 8:
3294     case 7:
3295     {
3296       b.Reset();
3297       CPacketTcp_Handshake_v7 p_in(&b);
3298       nUin = p_in.SourceUin();
3299       snprintf(id, 16, "%lu", nUin);
3300       userId = Licq::UserId(myOwnerId, id);
3301 
3302       unsigned long nCookie;
3303       {
3304         UserReadGuard u(userId);
3305         if (!u.isLocked() && !bChat)
3306         {
3307           gLog.warning(tr("Connection from unknown user."));
3308           return false;
3309         }
3310         nCookie = u.isLocked() ? u->Cookie() : 0;
3311       }
3312 
3313       if (nCookie != p_in.SessionId())
3314       {
3315         gLog.warning(tr("Spoofed connection from %s as uin %s."),
3316             s->getRemoteIpString().c_str(), userId.toString().c_str());
3317         return false;
3318       }
3319 
3320       // Send the ack
3321       CPacketTcp_Handshake_Ack p_ack;
3322       if (!s->send(*p_ack.getBuffer()))
3323         goto sock_error;
3324 
3325       // Send the handshake
3326       CPacketTcp_Handshake_v7 p_out(nUin, p_in.SessionId(), nPort);
3327       if (!s->send(*p_out.getBuffer()))
3328         goto sock_error;
3329 
3330       // Wait for the ack (this is very bad form...blocking recv here)
3331       s->ClearRecvBuffer();
3332       do
3333       {
3334         if (!s->RecvPacket()) goto sock_error;
3335       } while (!s->RecvBufferFull());
3336 
3337       if (s->RecvBuffer().getDataSize() != 6)
3338       {
3339         gLog.warning(tr("Handshake ack not the right size."));
3340         return false;
3341       }
3342 
3343       s->RecvBuffer().unpackUInt16LE(); // Packet length
3344       unsigned long nOk = s->RecvBuffer().UnpackUnsignedLong();
3345       if (nOk != 1)
3346       {
3347         gLog.warning(tr("Bad handshake ack: %ld."), nOk);
3348         return false;
3349       }
3350 
3351       if (bConfirm)
3352       {
3353         if (p_in.Id() == 0)
3354         {
3355           if (!Handshake_RecvConfirm_v7(s))
3356           goto sock_error;
3357         }
3358         else
3359         {
3360           pthread_mutex_lock(&mutex_reverseconnect);
3361           std::list<CReverseConnectToUserData *>::iterator iter;
3362           for (iter = m_lReverseConnect.begin(); ; ++iter)
3363           {
3364             if (iter == m_lReverseConnect.end())
3365             {
3366               gLog.warning(tr("Reverse connection with unknown id (%lu)"), p_in.Id());
3367               pthread_mutex_unlock(&mutex_reverseconnect);
3368               return false;
3369             }
3370             if ((*iter)->nId == p_in.Id() && (*iter)->myIdString == id)
3371             {
3372               s->setChannel((*iter)->nData);
3373               (*iter)->bSuccess = true;
3374               (*iter)->bFinished = true;
3375               if (!Handshake_SendConfirm_v7(s))
3376               {
3377                 pthread_mutex_unlock(&mutex_reverseconnect);
3378                 return false;
3379               }
3380               break;
3381             }
3382           }
3383           pthread_mutex_unlock(&mutex_reverseconnect);
3384         }
3385       }
3386 
3387       nVersion = IcqProtocol::dcVersionToUse(nVersionMajor);
3388 
3389       break;
3390     }
3391 
3392     case 6:
3393     {
3394       b.Reset();
3395       CPacketTcp_Handshake_v6 p_in(&b);
3396       nUin = p_in.SourceUin();
3397       snprintf(id, 16, "%lu", nUin);
3398       userId = Licq::UserId(myOwnerId, id);
3399 
3400       unsigned long nCookie;
3401       {
3402         UserReadGuard u(userId);
3403         if (!u.isLocked())
3404         {
3405           gLog.warning(tr("Connection from unknown user."));
3406           return false;
3407         }
3408         nCookie = u->Cookie();
3409       }
3410 
3411       if (nCookie != p_in.SessionId())
3412       {
3413         gLog.warning(tr("Spoofed connection from %s as uin %s."),
3414             s->getRemoteIpString().c_str(), userId.toString().c_str());
3415         return false;
3416       }
3417 
3418       // Send the ack
3419       CPacketTcp_Handshake_Ack p_ack;
3420       if (!s->send(*p_ack.getBuffer()))
3421         goto sock_error;
3422 
3423       // Send the handshake
3424       CPacketTcp_Handshake_v6 p_out(nUin, p_in.SessionId(), nPort);
3425       if (!s->send(*p_out.getBuffer()))
3426         goto sock_error;
3427 
3428       // Wait for the ack (this is very bad form...blocking recv here)
3429       s->ClearRecvBuffer();
3430       do
3431       {
3432         if (!s->RecvPacket()) goto sock_error;
3433       } while (!s->RecvBufferFull());
3434       s->RecvBuffer().unpackUInt16LE(); // Packet length
3435       unsigned long nOk = s->RecvBuffer().UnpackUnsignedLong();
3436       s->ClearRecvBuffer();
3437       if (nOk != 1)
3438       {
3439         gLog.warning(tr("Bad handshake ack: %ld."), nOk);
3440         return false;
3441       }
3442       nVersion = 6;
3443 
3444       pthread_mutex_lock(&mutex_reverseconnect);
3445       std::list<CReverseConnectToUserData *>::iterator iter;
3446       for (iter = m_lReverseConnect.begin(); iter != m_lReverseConnect.end();
3447         ++iter)
3448       {
3449         // For v6 there is no connection id, so just use uin
3450         if ((*iter)->myIdString == id)
3451         {
3452           (*iter)->bSuccess = true;
3453           (*iter)->bFinished = true;
3454           break;
3455         }
3456       }
3457       pthread_mutex_unlock(&mutex_reverseconnect);
3458 
3459       break;
3460     }
3461 
3462     case 5:
3463     case 4:
3464     {
3465       b.UnpackUnsignedLong(); // port number
3466       nUin = b.UnpackUnsignedLong();
3467       snprintf(id, 16, "%lu", nUin);
3468       userId = Licq::UserId(myOwnerId, id);
3469       nVersion = IcqProtocol::dcVersionToUse(nVersionMajor);
3470 
3471       unsigned long nIntIp;
3472       unsigned long nIp;
3473       {
3474         Licq::UserReadGuard u(userId);
3475         if (!u.isLocked())
3476         {
3477           gLog.warning(tr("Connection from unknown user."));
3478           return false;
3479         }
3480         nIntIp = u->IntIp();
3481         nIp = u->Ip();
3482       }
3483       /* This might prevent connections from clients behind assymetric
3484          connections (i.e. direct to ICQ server and through socks to clients)
3485          but they should be using v6+ anyway */
3486       if (nIntIp != s->getRemoteIpInt() && nIp != s->getRemoteIpInt())
3487       {
3488         gLog.warning(tr("Connection from %s as %s possible spoof."),
3489             s->getRemoteIpString().c_str(), userId.toString().c_str());
3490         return false;
3491       }
3492 
3493       pthread_mutex_lock(&mutex_reverseconnect);
3494       std::list<CReverseConnectToUserData *>::iterator iter;
3495       for (iter = m_lReverseConnect.begin(); iter != m_lReverseConnect.end();
3496         ++iter)
3497       {
3498         // For v4 there is no connection id, so just use uin
3499         if ((*iter)->myIdString == id)
3500         {
3501           (*iter)->bSuccess = true;
3502           (*iter)->bFinished = true;
3503           break;
3504         }
3505       }
3506       pthread_mutex_unlock(&mutex_reverseconnect);
3507 
3508       break;
3509     }
3510 
3511     case 3:
3512     case 2:
3513     case 1:
3514     {
3515       b.UnpackUnsignedLong(); // port number
3516       nUin = b.UnpackUnsignedLong();
3517       snprintf(id, 16, "%lu", nUin);
3518       userId = Licq::UserId(myOwnerId, id);
3519       nVersion = 2;
3520 
3521       unsigned long nIntIp;
3522       unsigned long nIp;
3523       {
3524         Licq::UserReadGuard u(userId);
3525         if (!u.isLocked())
3526         {
3527           gLog.warning(tr("Connection from unknown user."));
3528           return false;
3529         }
3530         nIntIp = u->IntIp();
3531         nIp = u->Ip();
3532       }
3533 
3534       /* This might prevent connections from clients behind assymetric
3535          connections (i.e. direct to ICQ server and through socks to clients)
3536          but they should be using v6+ anyway */
3537       if (nIntIp != s->getRemoteIpInt() && nIp != s->getRemoteIpInt())
3538       {
3539         gLog.warning(tr("Connection from %s as %s possible spoof."),
3540             s->getRemoteIpString().c_str(), userId.toString().c_str());
3541         return false;
3542       }
3543 
3544       pthread_mutex_lock(&mutex_reverseconnect);
3545       std::list<CReverseConnectToUserData *>::iterator iter;
3546       for (iter = m_lReverseConnect.begin(); iter != m_lReverseConnect.end();
3547         ++iter)
3548       {
3549         // For v2 there is no connection id, so just use uin
3550         if ((*iter)->myIdString == id)
3551         {
3552           (*iter)->bSuccess = true;
3553           (*iter)->bFinished = true;
3554           break;
3555         }
3556       }
3557       pthread_mutex_unlock(&mutex_reverseconnect);
3558 
3559       break;
3560     }
3561 
3562     default:
3563       b.log(Log::Unknown, "Unknown TCP handshake packet");
3564       return false;
3565   }
3566 
3567   s->setUserId(userId);
3568   s->SetVersion(nVersion);
3569 
3570   return true;
3571 
3572 sock_error:
3573   if (s->Error() == 0)
3574     gLog.warning(tr("Handshake error, remote side closed connection."));
3575   else
3576     gLog.warning(tr("Handshake socket error: %s."), s->errorStr().c_str());
3577   return false;
3578 }
3579 
Handshake_SendConfirm_v7(DcSocket * s)3580 bool IcqProtocol::Handshake_SendConfirm_v7(DcSocket* s)
3581 {
3582   // Send handshake accepted
3583   CPacketTcp_Handshake_Confirm p_confirm(s->channel(), 0);
3584   if (!s->send(*p_confirm.getBuffer()))
3585     return false;
3586 
3587   // Wait for reverse handshake accepted
3588   s->ClearRecvBuffer();
3589   do
3590   {
3591     if (!s->RecvPacket())
3592       return false;
3593   } while (!s->RecvBufferFull());
3594   s->ClearRecvBuffer();
3595 
3596   return true;
3597 }
3598 
Handshake_RecvConfirm_v7(DcSocket * s)3599 bool IcqProtocol::Handshake_RecvConfirm_v7(DcSocket* s)
3600 {
3601   // Get handshake confirmation
3602   s->ClearRecvBuffer();
3603   do
3604   {
3605     if (!s->RecvPacket()) goto sock_error;
3606   } while (!s->RecvBufferFull());
3607 
3608   { // damn scoping
3609     CBuffer &b = s->RecvBuffer();
3610     if (b.getDataSize() != 35)
3611     {
3612       gLog.warning(tr("Handshake confirm not the right size."));
3613       return false;
3614     }
3615     b.unpackUInt16LE(); // Packet length
3616     unsigned char c = b.UnpackChar();
3617     unsigned long l = b.UnpackUnsignedLong();
3618     if (c != 0x03 || l != 0x0000000A)
3619     {
3620       gLog.warning(tr("Unknown handshake response %2X,%8lX."), c, l);
3621       return false;
3622     }
3623     b.Reset();
3624     CPacketTcp_Handshake_Confirm p_confirm_in(&b);
3625     if (p_confirm_in.channel() != DcSocket::ChannelUnknown)
3626       s->setChannel(p_confirm_in.channel());
3627     else
3628     {
3629       gLog.warning(tr("Unknown channel in ack packet."));
3630       return false;
3631     }
3632 
3633     s->ClearRecvBuffer();
3634 
3635     CPacketTcp_Handshake_Confirm p_confirm_out(p_confirm_in.channel(),
3636                                                        p_confirm_in.Id());
3637 
3638     if (s->send(*p_confirm_out.getBuffer()))
3639       return true;
3640   }
3641 
3642  sock_error:
3643   if (s->Error() == 0)
3644     gLog.warning(tr("Handshake error, remote side closed connection."));
3645   else
3646     gLog.warning(tr("Handshake socket error: %s."), s->errorStr().c_str());
3647   return false;
3648 }
3649 
3650 /*------------------------------------------------------------------------------
3651  * ProcessTcpHandshake
3652  *
3653  * Takes the first buffer from a socket and parses it as a icq handshake.
3654  * Does not check that the given user already has a socket or not.
3655  *----------------------------------------------------------------------------*/
ProcessTcpHandshake(DcSocket * s)3656 bool IcqProtocol::ProcessTcpHandshake(DcSocket* s)
3657 {
3658   if (!Handshake_Recv(s, 0)) return false;
3659   Licq::UserId userId = s->userId();
3660   if (!userId.isValid())
3661     return false;
3662 
3663   UserWriteGuard u(userId);
3664   if (u.isLocked())
3665   {
3666     gLog.info(tr("Connection from %s (%s) [v%ld]."),
3667         u->getAlias().c_str(), userId.toString().c_str(), s->Version());
3668     if (u->socketDesc(s->channel()) != s->Descriptor())
3669     {
3670       if (u->socketDesc(s->channel()) != -1)
3671       {
3672         gLog.warning(tr("User %s (%s) already has an associated socket."),
3673             u->getAlias().c_str(), userId.toString().c_str());
3674         return true;
3675 /*        gSocketManager.CloseSocket(u->socketDesc(s->channel()), false);
3676         u->clearSocketDesc(s);*/
3677       }
3678       u->setSocketDesc(s);
3679     }
3680   }
3681   else
3682   {
3683     gLog.info(tr("Connection from new user (%s) [v%ld]."),
3684         userId.toString().c_str(), s->Version());
3685   }
3686 
3687   //awaken waiting threads, maybe unnecessarily, but doesn't hurt
3688   pthread_cond_broadcast(&cond_reverseconnect_done);
3689 
3690   return true;
3691 }
3692