1 /*
2  * This file is part of Licq, an instant messaging client for UNIX.
3  * Copyright (C) 1998-2014 Licq developers <licq-dev@googlegroups.com>
4  *
5  * Licq is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Licq is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Licq; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include "icq.h"
21 
22 #include <boost/foreach.hpp>
23 #include <cassert>
24 #include <cerrno>
25 #include <cstdio>
26 #include <cstdlib>
27 #include <ctime>
28 #include <sys/stat.h>
29 
30 #include <licq/contactlist/group.h>
31 #include <licq/contactlist/usermanager.h>
32 #include <licq/daemon.h>
33 #include <licq/event.h>
34 #include <licq/inifile.h>
35 #include <licq/logging/log.h>
36 #include <licq/statistics.h>
37 #include <licq/oneventmanager.h>
38 #include <licq/plugin/pluginmanager.h>
39 #include <licq/pluginsignal.h>
40 #include <licq/protocolmanager.h>
41 #include <licq/protocolsignal.h>
42 #include <licq/proxy.h>
43 #include <licq/translator.h>
44 #include <licq/userevents.h>
45 
46 #include "defines.h"
47 #include "gettext.h"
48 #include "oscarservice.h"
49 #include "owner.h"
50 #include "packet-srv.h"
51 #include "packet-tcp.h"
52 #include "protocolsignal.h"
53 #include "socket.h"
54 #include "user.h"
55 
56 using namespace LicqIcq;
57 using Licq::Daemon;
58 using Licq::IcqPluginActive;
59 using Licq::IcqPluginBusy;
60 using Licq::IcqPluginInactive;
61 using Licq::Log;
62 using Licq::OnEventData;
63 using Licq::gDaemon;
64 using Licq::gLog;
65 using Licq::gOnEventManager;
66 using Licq::gPluginManager;
67 using Licq::gTranslator;
68 using std::list;
69 using std::string;
70 using std::vector;
71 
72 // list of plugins we currently support
73 const struct PluginList IcqProtocol::info_plugins[] =
74 {
75   { "Picture"   , PLUGIN_PICTURE   , "Picture"                          },
76   { "Phone Book", PLUGIN_PHONExBOOK, "Phone Book / Phone \"Follow Me\"" }
77 };
78 
79 const struct PluginList IcqProtocol::status_plugins[] =
80 {
81   {"Phone \"Follow Me\"", PLUGIN_FOLLOWxME, "Phone Book / Phone \"Follow Me\""},
82   { "Shared Files Directory", PLUGIN_FILExSERVER, "Shared Files Directory" },
83   { "ICQphone Status"       , PLUGIN_ICQxPHONE  , "ICQphone Status"        }
84 };
85 
86 
87 std::list <CReverseConnectToUserData *> IcqProtocol::m_lReverseConnect;
88 pthread_mutex_t IcqProtocol::mutex_reverseconnect = PTHREAD_MUTEX_INITIALIZER;
89 pthread_cond_t IcqProtocol::cond_reverseconnect_done = PTHREAD_COND_INITIALIZER;
90 
91 
92 LicqIcq::IcqProtocol LicqIcq::gIcqProtocol;
93 Licq::SocketManager gSocketManager;
94 
IcqProtocol()95 IcqProtocol::IcqProtocol()
96   : myDirectMode(true)
97 {
98   // Empty
99 }
100 
~IcqProtocol()101 IcqProtocol::~IcqProtocol()
102 {
103   // Empty
104 }
105 
initialize()106 void IcqProtocol::initialize()
107 {
108   // Initialise the data values
109   m_nTCPSocketDesc = -1;
110   m_nTCPSrvSocketDesc = -1;
111   m_eStatus = STATUS_OFFLINE_MANUAL;
112   //just in case we need to sign on automatically
113   m_nDesiredStatus = ICQ_STATUS_ONLINE;
114   m_bRegistering = false;
115   m_nServerAck = 0;
116   m_bLoggingOn = false;
117   m_bOnlineNotifies = true;
118   m_bVerify = false;
119   m_bNeedSalt = true;
120   m_nRegisterThreadId = 0;
121 
122   receivedUserList.clear();
123 
124   myMaxUsersPerPacket = 100;
125 
126   // Proxy
127   m_xProxy = NULL;
128 
129   // Services
130   m_xBARTService = NULL;
131   thread_ping = thread_updateusers = thread_ssbiservice = 0;
132 
133   // Start up our threads
134   pthread_mutex_init(&mutex_runningevents, NULL);
135   pthread_mutex_init(&mutex_extendedevents, NULL);
136   pthread_mutex_init(&mutex_sendqueue_server, NULL);
137   pthread_mutex_init(&mutex_modifyserverusers, NULL);
138   pthread_mutex_init(&mutex_cancelthread, NULL);
139   pthread_cond_init(&cond_serverack, NULL);
140   pthread_mutex_init(&mutex_serverack, NULL);
141 }
142 
start()143 bool IcqProtocol::start()
144 {
145   MonitorSockets_func();
146 
147   // Cancel the ping thread
148   pthread_cancel(thread_ping);
149 
150   // Cancel the update users thread
151   pthread_cancel(thread_updateusers);
152 
153   // Cancel the BART service thread
154   if (m_xBARTService)
155     pthread_cancel(thread_ssbiservice);
156 
157   if (m_nTCPSrvSocketDesc != -1 )
158     icqLogoff();
159   if (m_nTCPSocketDesc != -1)
160     gSocketManager.CloseSocket(m_nTCPSocketDesc);
161 
162   return true;
163 }
164 
processSignal(const Licq::ProtocolSignal * s)165 void IcqProtocol::processSignal(const Licq::ProtocolSignal* s)
166 {
167   assert(s->userId().protocolId() == ICQ_PPID);
168   // TODO: Unless signal is Logon also make sure s->userId() belongs to myOwnerId
169 
170   switch (s->signal())
171   {
172     case Licq::ProtocolSignal::SignalLogon:
173     {
174       const Licq::ProtoLogonSignal* sig =
175           dynamic_cast<const Licq::ProtoLogonSignal*>(s);
176       logon(s->userId(), sig->status());
177       break;
178     }
179     case Licq::ProtocolSignal::SignalLogoff:
180       icqLogoff();
181       break;
182     case Licq::ProtocolSignal::SignalChangeStatus:
183     {
184       const Licq::ProtoChangeStatusSignal* sig =
185           dynamic_cast<const Licq::ProtoChangeStatusSignal*>(s);
186       setStatus(sig->status());
187       break;
188     }
189     case Licq::ProtocolSignal::SignalAddUser:
190       icqAddUser(s->userId(), false);
191       break;
192     case Licq::ProtocolSignal::SignalRemoveUser:
193       icqRemoveUser(s->userId());
194       Licq::gUserManager.removeLocalUser(s->userId());
195       break;
196     case Licq::ProtocolSignal::SignalRenameUser:
197       icqRenameUser(s->userId());
198       break;
199     case Licq::ProtocolSignal::SignalChangeUserGroups:
200       icqChangeGroup(s->userId());
201       break;
202     case Licq::ProtocolSignal::SignalSendMessage:
203       icqSendMessage(dynamic_cast<const Licq::ProtoSendMessageSignal*>(s));
204       break;
205     case Licq::ProtocolSignal::SignalNotifyTyping:
206     {
207       const Licq::ProtoTypingNotificationSignal* sig =
208           dynamic_cast<const Licq::ProtoTypingNotificationSignal*>(s);
209       icqTypingNotification(s->userId(), sig->active());
210       break;
211     }
212     case Licq::ProtocolSignal::SignalGrantAuth:
213       icqAuthorizeGrant(s);
214       break;
215     case Licq::ProtocolSignal::SignalRefuseAuth:
216       icqAuthorizeRefuse(dynamic_cast<const Licq::ProtoRefuseAuthSignal*>(s));
217       break;
218     case Licq::ProtocolSignal::SignalRequestInfo:
219       icqRequestMetaInfo(s->userId(), s);
220       break;
221     case Licq::ProtocolSignal::SignalUpdateInfo:
222       icqSetGeneralInfo(s);
223       break;
224     case Licq::ProtocolSignal::SignalRequestPicture:
225       icqRequestPicture(s);
226       break;
227     case Licq::ProtocolSignal::SignalBlockUser:
228       icqAddToInvisibleList(s->userId());
229       break;
230     case Licq::ProtocolSignal::SignalUnblockUser:
231       icqRemoveFromInvisibleList(s->userId());
232       break;
233     case Licq::ProtocolSignal::SignalAcceptUser:
234       icqAddToVisibleList(s->userId());
235       break;
236     case Licq::ProtocolSignal::SignalUnacceptUser:
237       icqRemoveFromVisibleList(s->userId());
238       break;
239     case Licq::ProtocolSignal::SignalIgnoreUser:
240       icqAddToIgnoreList(s->userId());
241       break;
242     case Licq::ProtocolSignal::SignalUnignoreUser:
243       icqRemoveFromIgnoreList(s->userId());
244       break;
245     case Licq::ProtocolSignal::SignalSendFile:
246       icqFileTransfer(dynamic_cast<const Licq::ProtoSendFileSignal*>(s));
247       break;
248     case Licq::ProtocolSignal::SignalCancelEvent:
249       CancelEvent(s->eventId());
250       break;
251     case Licq::ProtocolSignal::SignalSendReply:
252     {
253       const Licq::ProtoSendEventReplySignal* sig =
254           dynamic_cast<const Licq::ProtoSendEventReplySignal*>(s);
255       if (sig->accept())
256         icqFileTransferAccept(sig);
257       else
258         icqFileTransferRefuse(sig);
259       break;
260     }
261     case Licq::ProtocolSignal::SignalOpenSecure:
262       icqOpenSecureChannel(s);
263       break;
264     case Licq::ProtocolSignal::SignalCloseSecure:
265       icqCloseSecureChannel(s);
266       break;
267     case Licq::ProtocolSignal::SignalRequestAuth:
268     {
269       const Licq::ProtoRequestAuthSignal* sig =
270           dynamic_cast<const Licq::ProtoRequestAuthSignal*>(s);
271       icqRequestAuth(s->userId(), sig->message());
272       break;
273     }
274     case Licq::ProtocolSignal::SignalRenameGroup:
275       gIcqProtocol.icqRenameGroup(
276           dynamic_cast<const Licq::ProtoRenameGroupSignal*>(s));
277       break;
278     case Licq::ProtocolSignal::SignalRemoveGroup:
279       gIcqProtocol.icqRemoveGroup(
280           dynamic_cast<const Licq::ProtoRemoveGroupSignal*>(s));
281       break;
282     case Licq::ProtocolSignal::SignalSendUrl:
283       icqSendUrl(dynamic_cast<const Licq::ProtoSendUrlSignal*>(s));
284       break;
285     case Licq::ProtocolSignal::SignalProtocolSpecific:
286     {
287       const ProtocolSignal* ips = dynamic_cast<const ProtocolSignal*>(s);
288       assert(ips != NULL);
289       switch (ips->icqSignal())
290       {
291         case ProtocolSignal::SignalIcqSendContacts:
292           icqSendContactList(
293               dynamic_cast<const ProtoSendContactsSignal*>(ips));
294           break;
295         case ProtocolSignal::SignalIcqFetchAutoResponse:
296           icqFetchAutoResponse(s);
297           break;
298         case ProtocolSignal::SignalIcqChatRequest:
299           icqChatRequest(dynamic_cast<const ProtoChatRequestSignal*>(ips));
300           break;
301         case ProtocolSignal::SignalIcqChatRefuse:
302           icqChatRequestRefuse(
303               dynamic_cast<const ProtoChatRefuseSignal*>(ips));
304           break;
305         case ProtocolSignal::SignalIcqChatAccept:
306           icqChatRequestAccept(
307               dynamic_cast<const ProtoChatAcceptSignal*>(ips));
308           break;
309         case ProtocolSignal::SignalIcqRequestPlugin:
310         {
311           const ProtoRequestPluginSignal* sig =
312               dynamic_cast<const ProtoRequestPluginSignal*>(ips);
313           icqRequestPluginInfo(s->userId(), sig->type(), sig->direct(), s);
314           break;
315         }
316         case ProtocolSignal::SignalIcqUpdateWork:
317           icqSetWorkInfo(dynamic_cast<const ProtoUpdateWorkSignal*>(ips));
318           break;
319         case ProtocolSignal::SignalIcqUpdateEmail:
320           icqSetEmailInfo(dynamic_cast<const ProtoUpdateEmailSignal*>(ips));
321           break;
322         case ProtocolSignal::SignalIcqUpdateMore:
323           icqSetMoreInfo(dynamic_cast<const ProtoUpdateMoreSignal*>(ips));
324           break;
325         case ProtocolSignal::SignalIcqUpdateSecurity:
326           icqSetSecurityInfo(
327               dynamic_cast<const ProtoUpdateSecuritySignal*>(ips));
328           break;
329         case ProtocolSignal::SignalIcqUpdateInterests:
330           icqSetInterestsInfo(
331               dynamic_cast<const ProtoUpdateInterestsSignal*>(ips));
332           break;
333         case ProtocolSignal::SignalIcqUpdateOrgBack:
334           icqSetOrgBackInfo(
335               dynamic_cast<const ProtoUpdateOrgBackSignal*>(ips));
336           break;
337         case ProtocolSignal::SignalIcqUpdateAbout:
338           icqSetAbout(dynamic_cast<const ProtoUpdateAboutSignal*>(ips));
339           break;
340         case ProtocolSignal::SignalIcqSearchWhitePages:
341           icqSearchWhitePages(
342               dynamic_cast<const ProtoSearchWhitePagesSignal*>(ips));
343           break;
344         case ProtocolSignal::SignalIcqSearchUin:
345           icqSearchByUin(dynamic_cast<const ProtoSearchUinSignal*>(ips));
346           break;
347         case ProtocolSignal::SignalIcqNotifyAdded:
348           icqAlertUser(s->userId());
349           break;
350         case ProtocolSignal::SignalIcqUpdateTimestamp:
351           icqUpdateInfoTimestamp(
352               dynamic_cast<const ProtoUpdateTimestampSignal*>(ips));
353           break;
354         case ProtocolSignal::SignalIcqSetPhoneFollowMe:
355           icqSetPhoneFollowMeStatus(
356               dynamic_cast<const ProtoSetPhoneFollowMeSignal*>(ips)->status());
357           break;
358         case ProtocolSignal::SignalIcqUpdateRandomChat:
359           setRandomChatGroup(
360               dynamic_cast<const ProtoUpdateRandomChatSignal*>(ips));
361           break;
362         case ProtocolSignal::SignalIcqSearchRandom:
363           randomChatSearch(
364               dynamic_cast<const ProtoSearchRandomSignal*>(ips));
365           break;
366         case ProtocolSignal::SignalIcqUpdateUsers:
367           updateAllUsersInGroup(
368               dynamic_cast<const ProtoUpdateUsersSignal*>(ips)->groupId());
369           break;
370         default:
371           // All of these signals are defined within icq protocol
372           // If we get here something is broken
373           assert(false);
374       }
375       break;
376     }
377     default:
378     {
379       /* Unsupported action, if it has an eventId, cancel it */
380       if (s->eventId() != 0)
381         Licq::gPluginManager.pushPluginEvent(
382             new Licq::Event(s, Licq::Event::ResultUnsupported));
383       break;
384     }
385   }
386 }
387 
directMode() const388 bool IcqProtocol::directMode() const
389 {
390   return (!gDaemon.behindFirewall() || (gDaemon.behindFirewall() && gDaemon.tcpEnabled()));
391 }
392 
InitProxy()393 void IcqProtocol::InitProxy()
394 {
395   if (m_xProxy != NULL)
396   {
397     delete m_xProxy;
398     m_xProxy = NULL;
399   }
400   m_xProxy = gDaemon.createProxy();
401 }
402 
dcVersionToUse(unsigned short v_in)403 unsigned short IcqProtocol::dcVersionToUse(unsigned short v_in)
404 {
405   /*if (ICQ_VERSION_TCP & 4 && v & 4) return 4;
406   if (ICQ_VERSION_TCP & 2 && v & 2) return 2;
407   gLog.warning(tr("Unknown TCP version %d.  Attempting v2."), v);
408   return 2;*/
409   unsigned short v_out = v_in < ICQ_VERSION_TCP ? v_in : ICQ_VERSION_TCP;
410   if (v_out < 2 || v_out == 5)
411   {
412     if (v_out == 5)
413       v_out = 4;
414     else
415       v_out = 6;
416 
417     gLog.warning(tr("Invalid TCP version %d.  Attempting v%d."), v_in, v_out);
418   }
419   return v_out;
420 }
421 
422 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
423 
SetUseServerSideBuddyIcons(bool b)424 void IcqProtocol::SetUseServerSideBuddyIcons(bool b)
425 {
426   if (b && m_xBARTService == NULL)
427   {
428     m_xBARTService = new COscarService(ICQ_SNACxFAM_BART);
429     int nResult = pthread_create(&thread_ssbiservice, NULL,
430                                  &OscarServiceSendQueue_tep, m_xBARTService);
431     if (nResult != 0)
432     {
433       gLog.error(tr("Unable to start BART service thread:%s."), strerror(nResult));
434     }
435   }
436 
437   OwnerWriteGuard o(myOwnerId);
438   o->setUseBart(b);
439 }
440 
ChangeUserStatus(User * u,unsigned long s,time_t onlineSince)441 void IcqProtocol::ChangeUserStatus(User* u, unsigned long s, time_t onlineSince)
442 {
443   //This is the v6 way of telling us phone follow me status
444   if (s & ICQ_STATUS_FxPFM)
445   {
446     if (s & ICQ_STATUS_FxPFMxAVAILABLE)
447       u->setPhoneFollowMeStatus(IcqPluginActive);
448     else
449       u->setPhoneFollowMeStatus(IcqPluginBusy);
450   }
451   else if (u->Version() < 7)
452     u->setPhoneFollowMeStatus(IcqPluginInactive);
453 
454   u->setWebPresence(s & ICQ_STATUS_FxWEBxPRESENCE);
455   u->setHideIp(s & ICQ_STATUS_FxHIDExIP);
456   u->setBirthdayFlag(s & ICQ_STATUS_FxBIRTHDAY);
457   u->setHomepageFlag(s & ICQ_STATUS_FxICQxHOMEPAGE);
458 
459   if (s & ICQ_STATUS_FxDIRECTxDISABLED)
460     u->setDirectFlag(User::DirectDisabled);
461   else if (s & ICQ_STATUS_FxDIRECTxLISTED)
462     u->setDirectFlag(User::DirectListed);
463   else if (s & ICQ_STATUS_FxDIRECTxAUTH)
464     u->setDirectFlag(User::DirectAuth);
465   else
466     u->setDirectFlag(User::DirectAnyone);
467 
468   u->statusChanged(statusFromIcqStatus(s), onlineSince);
469 }
470 
eventCommandFromPacket(Licq::Packet * p)471 unsigned IcqProtocol::eventCommandFromPacket(Licq::Packet* p)
472 {
473   if (p->SubCommand() == ICQ_CMDxSUB_MSG)
474     return Licq::Event::CommandMessage;
475   if (p->SubCommand() == ICQ_CMDxSUB_URL)
476     return Licq::Event::CommandUrl;
477   if (p->SubCommand() == ICQ_CMDxSUB_FILE)
478     return Licq::Event::CommandFile;
479   if (p->SubCommand() == ICQ_CMDxSUB_CHAT)
480     return Licq::Event::CommandChatInvite;
481   if (p->SubCommand() == ICQ_CMDxSUB_SECURExOPEN)
482     return Licq::Event::CommandSecureOpen;
483   return Licq::Event::CommandOther;
484 }
485 
486 /*----------------------------------------------------------------------------
487  * CICQDaemon::SendEvent
488  *
489  * Sends an event without expecting a reply.
490  *--------------------------------------------------------------------------*/
491 
SendEvent_Server(CPacket * packet,const Licq::ProtocolSignal * ps)492 void IcqProtocol::SendEvent_Server(CPacket *packet, const Licq::ProtocolSignal* ps)
493 {
494 #if 1
495   Licq::Event* e;
496   if (ps == NULL)
497     e = new Licq::Event(m_nTCPSrvSocketDesc, packet, Licq::Event::ConnectServer);
498   else
499     e = new Licq::Event(ps->callerThread(), ps->eventId(), m_nTCPSrvSocketDesc, packet, Licq::Event::ConnectServer);
500   e->myCommand = eventCommandFromPacket(packet);
501 
502   pthread_mutex_lock(&mutex_sendqueue_server);
503   m_lxSendQueue_Server.push_back(e);
504   pthread_mutex_unlock(&mutex_sendqueue_server);
505 
506   e->m_NoAck = true;
507   int nResult = pthread_create(&e->thread_send, NULL, &ProcessRunningEvent_Server_tep, e);
508   if (nResult != 0)
509   {
510     gLog.error(tr("Unable to start server event thread (#%hu): %s."),
511         e->m_nSequence, strerror(nResult));
512     e->m_eResult = Licq::Event::ResultError;
513   }
514 #else
515   SendEvent(m_nTCPSrvSocketDesc, *packet, true);
516 #endif
517 }
518 
SendExpectEvent_Server(const Licq::ProtocolSignal * ps,const Licq::UserId & userId,CSrvPacketTcp * packet,Licq::UserEvent * ue,bool bExtendedEvent)519 Licq::Event* IcqProtocol::SendExpectEvent_Server(const Licq::ProtocolSignal* ps,
520     const Licq::UserId& userId, CSrvPacketTcp *packet, Licq::UserEvent *ue, bool bExtendedEvent)
521 {
522   // If we are already shutting down, don't start any events
523   if (gDaemon.shuttingDown())
524   {
525     if (packet != NULL) delete packet;
526     if (ue != NULL) delete ue;
527     return NULL;
528   }
529 
530   Licq::Event* e;
531   if (ps == NULL)
532     e = new Licq::Event(m_nTCPSrvSocketDesc, packet, Licq::Event::ConnectServer, userId, ue);
533   else
534     e = new Licq::Event(ps->callerThread(), ps->eventId(), m_nTCPSrvSocketDesc, packet,
535         Licq::Event::ConnectServer, userId, ue);
536   e->myCommand = eventCommandFromPacket(packet);
537 
538   if (bExtendedEvent) PushExtendedEvent(e);
539 
540   Licq::Event *result = SendExpectEvent(e, &ProcessRunningEvent_Server_tep);
541 
542   // if an error occured, remove the event from the extended queue as well
543   if (result == NULL && bExtendedEvent)
544   {
545     pthread_mutex_lock(&mutex_extendedevents);
546     std::list<Licq::Event*>::iterator i;
547     for (i = m_lxExtendedEvents.begin(); i != m_lxExtendedEvents.end(); ++i)
548     {
549       if (*i == e)
550       {
551         m_lxExtendedEvents.erase(i);
552         break;
553       }
554     }
555     pthread_mutex_unlock(&mutex_extendedevents);
556   }
557 
558   return result;
559 }
560 
SendExpectEvent_Client(const Licq::ProtocolSignal * ps,const User * pUser,CPacketTcp * packet,Licq::UserEvent * ue)561 Licq::Event* IcqProtocol::SendExpectEvent_Client(const Licq::ProtocolSignal* ps, const User* pUser,
562     CPacketTcp* packet, Licq::UserEvent *ue)
563 {
564   // If we are already shutting down, don't start any events
565   if (gDaemon.shuttingDown())
566   {
567     if (packet != NULL) delete packet;
568     if (ue != NULL) delete ue;
569     return NULL;
570   }
571 
572   Licq::Event* e;
573   if (ps == NULL)
574     e = new Licq::Event(pUser->socketDesc(packet->channel()), packet, Licq::Event::ConnectUser,
575         pUser->id(), ue);
576   else
577     e = new Licq::Event(ps->callerThread(), ps->eventId(), pUser->socketDesc(packet->channel()),
578         packet, Licq::Event::ConnectUser, pUser->id(), ue);
579   e->myCommand = eventCommandFromPacket(packet);
580   e->myFlags |= Licq::Event::FlagDirect;
581 
582   return SendExpectEvent(e, &ProcessRunningEvent_Client_tep);
583 }
584 
585 
SendExpectEvent(Licq::Event * e,void * (* fcn)(void *))586 Licq::Event* IcqProtocol::SendExpectEvent(Licq::Event* e, void *(*fcn)(void *))
587 {
588   // don't release the mutex until thread is running so that cancelling the
589   // event cancels the thread as well
590   pthread_mutex_lock(&mutex_runningevents);
591   m_lxRunningEvents.push_back(e);
592 
593   assert(e);
594 
595   if (fcn == ProcessRunningEvent_Server_tep)
596   {
597     pthread_mutex_lock(&mutex_sendqueue_server);
598     m_lxSendQueue_Server.push_back(e);
599     pthread_mutex_unlock(&mutex_sendqueue_server);
600   }
601 
602   int nResult = pthread_create(&e->thread_send, NULL, fcn, e);
603   if (fcn != ProcessRunningEvent_Server_tep)
604     e->thread_running = true;
605   pthread_mutex_unlock(&mutex_runningevents);
606 
607   if (nResult != 0)
608   {
609     gLog.error(tr("Unable to start event thread (#%hu): %s."),
610         e->m_nSequence, strerror(nResult));
611     DoneEvent(e, Licq::Event::ResultError);
612     if (e->m_nSocketDesc == m_nTCPSrvSocketDesc)
613     {
614       pthread_mutex_lock(&mutex_sendqueue_server);
615       list<Licq::Event*>::iterator iter;
616       for (iter = m_lxSendQueue_Server.begin();
617            iter != m_lxSendQueue_Server.end(); ++iter)
618       {
619         if (e == *iter)
620         {
621           m_lxSendQueue_Server.erase(iter);
622 
623           Licq::Event* cancelled = new Licq::Event(e);
624           cancelled->m_bCancelled = true;
625           m_lxSendQueue_Server.push_back(cancelled);
626           break;
627         }
628       }
629       pthread_mutex_unlock(&mutex_sendqueue_server);
630     }
631     ProcessDoneEvent(e);
632     return NULL;
633   }
634 
635   return (e);
636 }
637 
638 
639 //---SendEvent-----------------------------------------------------------------
640 /*! \brief Sends an event without expecting a reply
641  *
642  * Sends an event without expecting a reply, does not create an event
643  * structure, and does not attempt a connection if the socket is invalid.
644  * Can possibly block on send, but this is ok as it is never called from the
645  * gui thread.
646  * Note that the user who owns the given socket is probably read-locked at
647  * this point.
648  *
649  * \return Returns true on success, else returns false
650  */
SendEvent(int nSD,CPacket & p,bool d)651 bool IcqProtocol::SendEvent(int nSD, CPacket &p, bool d)
652 {
653   Licq::INetSocket* s = gSocketManager.FetchSocket(nSD);
654   if (s == NULL) return false;
655   bool r = SendEvent(s, p, d);
656   gSocketManager.DropSocket(s);
657   return r;
658 }
659 
SendEvent(Licq::INetSocket * pSock,CPacket & p,bool d)660 bool IcqProtocol::SendEvent(Licq::INetSocket* pSock, CPacket &p, bool d)
661 {
662   CBuffer *buf = p.Finalize(pSock);
663   pSock->send(*buf);
664   if (d) delete buf;
665   return true;
666 }
667 
668 
669 //---FailEvents----------------------------------------------------------------
670 /*! \brief Fails all events on the given socket. */
FailEvents(int sd,int err)671 void IcqProtocol::FailEvents(int sd, int err)
672 {
673   // Go through all running events and fail all from this socket
674   Licq::Event* e = NULL;
675   do
676   {
677     e = NULL;
678     pthread_mutex_lock(&mutex_runningevents);
679     list<Licq::Event*>::iterator iter;
680     for (iter = m_lxRunningEvents.begin(); iter != m_lxRunningEvents.end(); ++iter)
681     {
682       if ((*iter)->m_nSocketDesc == sd)
683       {
684         e = *iter;
685         break;
686       }
687     }
688     pthread_mutex_unlock(&mutex_runningevents);
689     if (e != NULL && DoneEvent(e, Licq::Event::ResultError) != NULL)
690     {
691       // If the connection was reset, we can try again
692       if (err == ECONNRESET)
693       {
694         e->m_nSocketDesc = -1;
695         // We have to decrypt the packet so we can re-encrypt it properly
696         Decrypt_Client(e->m_pPacket->getBuffer(),
697          ((CPacketTcp *)e->m_pPacket)->Version());
698         SendExpectEvent(e, &ProcessRunningEvent_Client_tep);
699       }
700       else
701       {
702         ProcessDoneEvent(e);
703       }
704     }
705   } while (e != NULL);
706 }
707 
708 /**
709  * Search the running event queue for a specific event by subsequence.
710  */
hasServerEvent(unsigned long _nSubSequence) const711 bool IcqProtocol::hasServerEvent(unsigned long _nSubSequence) const
712 {
713   bool hasEvent = false;
714   pthread_mutex_lock(&mutex_runningevents);
715   list<Licq::Event*>::const_iterator iter;
716   for (iter = m_lxRunningEvents.begin(); iter != m_lxRunningEvents.end(); ++iter)
717   {
718     if ((*iter)->CompareSubSequence(_nSubSequence))
719     {
720       hasEvent = true;
721       break;
722     }
723   }
724 
725   pthread_mutex_unlock(&mutex_runningevents);
726   return hasEvent;
727 }
728 
729 
730 //---DoneSrvEvent--------------------------------------------------------------
731 /*! \brief Marks the given event as done.
732  *
733  * Marks the given event as done and removes it from the running events list.
734  * This is for new OSCAR server events.
735  * Basically this is DoneEvent (2)
736  */
DoneServerEvent(unsigned long _nSubSeq,Licq::Event::ResultType _eResult)737 Licq::Event* IcqProtocol::DoneServerEvent(unsigned long _nSubSeq, Licq::Event::ResultType _eResult)
738 {
739   pthread_mutex_lock(&mutex_runningevents);
740   Licq::Event* e = NULL;
741   list<Licq::Event*>::iterator iter;
742   for (iter = m_lxRunningEvents.begin(); iter != m_lxRunningEvents.end(); ++iter)
743   {
744     if ((*iter)->CompareSubSequence(_nSubSeq) )
745     {
746       e = *iter;
747       m_lxRunningEvents.erase(iter);
748       // Check if we should cancel a processing thread
749       if (e->thread_running && !pthread_equal(e->thread_send, pthread_self()))
750       {
751         pthread_mutex_lock(&mutex_cancelthread);
752         pthread_cancel(e->thread_send);
753         pthread_mutex_unlock(&mutex_cancelthread);
754         e->thread_running = false;
755       }
756       break;
757     }
758   }
759   pthread_mutex_unlock(&mutex_runningevents);
760 
761   // If we didn't find the event, it must have already been removed, we are too late
762 
763   if (e == NULL) return (NULL);
764 
765   e->m_eResult = _eResult;
766 
767   return(e);
768 }
769 
770 //---DoneEvent-----------------------------------------------------------------
771 /*! \brief Marks the given event as done.
772  *
773  * Marks the given event as done and removes it from the running events list.
774  */
DoneEvent(Licq::Event * e,Licq::Event::ResultType _eResult)775 Licq::Event* IcqProtocol::DoneEvent(Licq::Event* e, Licq::Event::ResultType _eResult)
776 {
777   pthread_mutex_lock(&mutex_runningevents);
778   list<Licq::Event*>::iterator iter;
779   bool bFound = false;
780   for (iter = m_lxRunningEvents.begin(); iter != m_lxRunningEvents.end(); ++iter)
781   {
782     if (e == *iter)
783     {
784       bFound = true;
785       m_lxRunningEvents.erase(iter);
786       // Check if we should cancel a processing thread
787       if (e->thread_running && !pthread_equal(e->thread_send, pthread_self()))
788       {
789         pthread_mutex_lock(&mutex_cancelthread);
790         pthread_cancel(e->thread_send);
791         pthread_mutex_unlock(&mutex_cancelthread);
792         e->thread_running = false;
793       }
794       break;
795     }
796   }
797 
798 #if 0
799   if (m_lxRunningEvents.size()) {
800     gLog.info(tr("doneevents: for: %p pending:"), e);
801     for (iter = m_lxRunningEvents.begin(); iter != m_lxRunningEvents.end(); ++iter)
802     {
803       gLog.info(tr("%p Command: %d SubCommand: %d Sequence: %hu SubSequence: %d: Uin: %lu"), *iter,
804                 (*iter)->Command(), (*iter)->SubCommand(), (*iter)->Sequence(), (*iter)->SubSequence(),
805                 (*iter)->Uin());
806     }
807   }
808 #endif
809 
810   //bool bFound = (iter == m_lxRunningEvents.end());
811   pthread_mutex_unlock(&mutex_runningevents);
812 
813   // If we didn't find the event, it must have already been removed, we are too late
814   if (!bFound) return (NULL);
815 
816   e->m_eResult = _eResult;
817 
818 #if 0
819 #if ICQ_VERSION == 5
820   if (_eResult == Licq::Event::ResultCancelled && e->m_nSocket == m_nUDPSocketDesc)
821   {
822     pthread_mutex_lock(&mutex_runningevents);
823     Licq::Event* e2 = new Licq::Event(e);
824     e2->m_bCancelled = true;
825     e2->m_xPacket = e->m_xPacket;
826     m_lxRunningEvents.push_back(e2);
827     pthread_mutex_unlock(&mutex_runningevents);
828   }
829   else
830 #endif
831 #endif
832 
833   return (e);
834 }
835 
836 /*------------------------------------------------------------------------------
837  * DoneEvent (2)
838  *
839  * Differs from above only in that it takes a socket descriptor and sequence
840  * instead of the event itself.  Thus it will be called from an acking thread
841  * as opposed to a timed out or cancelling thread.
842  * Note: There is a potential race condition here.  There is a time between
843  *       when this function is called and when it finally cancels any sending
844  *       thread during which the sending thread may continue to do stuff.
845  *       The result is extra sends or time out warnings.
846  *----------------------------------------------------------------------------*/
DoneEvent(int _nSD,unsigned short _nSequence,Licq::Event::ResultType _eResult)847 Licq::Event* IcqProtocol::DoneEvent(int _nSD, unsigned short _nSequence, Licq::Event::ResultType _eResult)
848 {
849   pthread_mutex_lock(&mutex_runningevents);
850   Licq::Event* e = NULL;
851   list<Licq::Event*>::iterator iter;
852   for (iter = m_lxRunningEvents.begin(); iter != m_lxRunningEvents.end(); ++iter)
853   {
854     if ((*iter)->CompareEvent(_nSD, _nSequence) )
855     {
856       e = *iter;
857       m_lxRunningEvents.erase(iter);
858       // Check if we should cancel a processing thread
859       if (e->thread_running && !pthread_equal(e->thread_send, pthread_self()))
860       {
861         pthread_mutex_lock(&mutex_cancelthread);
862         pthread_cancel(e->thread_send);
863         pthread_mutex_unlock(&mutex_cancelthread);
864         e->thread_running = false;
865       }
866       break;
867     }
868   }
869   pthread_mutex_unlock(&mutex_runningevents);
870 
871   // If we didn't find the event, it must have already been removed, we are too late
872   if (e == NULL) return (NULL);
873 
874   e->m_eResult = _eResult;
875 
876   return(e);
877 }
878 
DoneEvent(unsigned long tag,Licq::Event::ResultType _eResult)879 Licq::Event* IcqProtocol::DoneEvent(unsigned long tag, Licq::Event::ResultType _eResult)
880 {
881   pthread_mutex_lock(&mutex_runningevents);
882   Licq::Event* e = NULL;
883   list<Licq::Event*>::iterator iter;
884   for (iter = m_lxRunningEvents.begin(); iter != m_lxRunningEvents.end(); ++iter)
885   {
886     if ((*iter)->Equals(tag))
887     {
888       e = *iter;
889       m_lxRunningEvents.erase(iter);
890       // Check if we should cancel a processing thread
891       if (e->thread_running && !pthread_equal(e->thread_send, pthread_self()))
892       {
893         pthread_mutex_lock(&mutex_cancelthread);
894         pthread_cancel(e->thread_send);
895         pthread_mutex_unlock(&mutex_cancelthread);
896         e->thread_running = false;
897       }
898       break;
899     }
900   }
901   pthread_mutex_unlock(&mutex_runningevents);
902 
903   // If we didn't find the event, it must have already been removed, we are too late
904   if (e == NULL) return (NULL);
905 
906   e->m_eResult = _eResult;
907 
908   return(e);
909 }
910 
911 
912 /*------------------------------------------------------------------------------
913  * ProcessDoneEvent
914  *
915  * Processes the given event possibly passes the result to the gui.
916  *----------------------------------------------------------------------------*/
917 #if ICQ_VERSION < 8
ProcessDoneEvent(Licq::Event * e)918 void IcqProtocol::ProcessDoneEvent(Licq::Event* e)
919 {
920 #if ICQ_VERSION != 5
921   static unsigned short s_nPingTimeOuts = 0;
922 #endif
923 
924   // Determine this now as later we might have deleted the event
925   unsigned short nCommand = e->m_nCommand;
926   Licq::Event::ResultType eResult = e->m_eResult;
927 
928   // Write the event to the history file if appropriate
929   if (e->m_pUserEvent != NULL &&
930       e->m_eResult == Licq::Event::ResultAcked &&
931       e->subResult != Licq::Event::SubResultReturn)
932   {
933     Licq::UserReadGuard(e->userId());
934     if (u.isLocked())
935     {
936       e->m_pUserEvent->AddToHistory(*u, false);
937       u->SetLastSentEvent();
938       m_xOnEventManager.Do(ON_EVENT_MSGSENT, *u);
939     }
940     Licq::gStatistics.increase(Licq::Statistics::EventsSentCounter);
941   }
942 
943   // Process the event
944   switch (e->m_nCommand)
945   {
946   // Ping is always sent by the daemon
947   case ICQ_CMDxSND_PING:
948 #if ICQ_VERSION != 5
949       if (e->m_eResult == Licq::Event::ResultAcked)
950       s_nPingTimeOuts = 0;
951     else
952     {
953       s_nPingTimeOuts++;
954       if (s_nPingTimeOuts > MaxPingTimeouts)
955       {
956         s_nPingTimeOuts = 0;
957         icqRelogon();
958       }
959     }
960 #endif
961     break;
962   // Regular events
963   case ICQ_CMDxTCP_START:
964   case ICQ_CMDxSND_THRUxSERVER:
965   case ICQ_CMDxSND_USERxADD:
966   case ICQ_CMDxSND_USERxLIST:
967   case ICQ_CMDxSND_SYSxMSGxREQ:
968   case ICQ_CMDxSND_SYSxMSGxDONExACK:
969   case ICQ_CMDxSND_AUTHORIZE:
970   case ICQ_CMDxSND_VISIBLExLIST:
971   case ICQ_CMDxSND_INVISIBLExLIST:
972   case ICQ_CMDxSND_MODIFYxVIEWxLIST:
973       Licq::gPluginManager.pushPluginEvent(e);
974       break;
975 
976   case ICQ_CMDxSND_SETxSTATUS:
977       if (e->m_eResult == Licq::Event::ResultAcked)
978       {
979         Licq::OwnerWriteGuard o(myOwnerId);
980       ChangeUserStatus(o, ((CPU_SetStatus *)e->m_pPacket)->Status() );
981       }
982       Licq::gPluginManager.pushPluginEvent(e);
983       break;
984 
985   case ICQ_CMDxSND_SETxRANDOMxCHAT:
986       if (e->m_eResult == Licq::Event::ResultAcked)
987       {
988         Licq::OwnerWriteGuard o(myOwnerId);
989       o->SetRandomChatGroup(((CPU_SetRandomChatGroup *)e->m_pPacket)->Group());
990       }
991       Licq::gPluginManager.pushPluginEvent(e);
992       break;
993 
994   // Extended events
995   case ICQ_CMDxSND_LOGON:
996   case ICQ_CMDxSND_USERxGETINFO:
997   case ICQ_CMDxSND_USERxGETDETAILS:
998   case ICQ_CMDxSND_UPDATExDETAIL:
999   case ICQ_CMDxSND_UPDATExBASIC:
1000   case ICQ_CMDxSND_SEARCHxINFO:
1001   case ICQ_CMDxSND_SEARCHxUIN:
1002   case ICQ_CMDxSND_REGISTERxUSER:
1003   case ICQ_CMDxSND_META:
1004   case ICQ_CMDxSND_RANDOMxSEARCH:
1005   {
1006     switch (e->m_eResult)
1007     {
1008         case Licq::Event::ResultError:
1009         case Licq::Event::ResultTimedout:
1010         case Licq::Event::ResultFailed:
1011         case Licq::Event::ResultSuccess:
1012         case Licq::Event::ResultCancelled:
1013           Licq::gPluginManager.pushPluginEvent(e);
1014           break;
1015         case Licq::Event::ResultAcked:  // push to extended event list
1016         PushExtendedEvent(e);
1017         break;
1018         default:
1019           gLog.error(tr("Internal error: ProcessDoneEvents(): Invalid result for extended event (%d)."),
1020               e->m_eResult);
1021           delete e;
1022           return;
1023     }
1024     break;
1025   }
1026 
1027     default:
1028       gLog.error(tr("Internal error: ProcessDoneEvents(): Unknown command (%04X)."),
1029           e->m_nCommand);
1030       delete e;
1031       return;
1032   }
1033 
1034   // Some special commands to deal with
1035 #if ICQ_VERSION == 5
1036   if (nCommand != ICQ_CMDxTCP_START &&
1037       (eResult == Licq::Event::ResultTimedout || eResult == Licq::Event::ResultError) )
1038   {
1039     if (nCommand == ICQ_CMDxSND_LOGON)
1040     {
1041       m_bLoggingOn = false;
1042       m_eStatus = STATUS_OFFLINE_FORCED;
1043     }
1044     else
1045       icqRelogon();
1046   }
1047 #endif
1048 }
1049 #endif
1050 
1051 
1052 /*------------------------------------------------------------------------------
1053  * DoneExtendedEvent
1054  *
1055  * Tracks down the relevant extended event, removes it from the list, and
1056  * returns it, marking the result as appropriate.
1057  *----------------------------------------------------------------------------*/
DoneExtendedServerEvent(const unsigned short _nSubSequence,Licq::Event::ResultType _eResult)1058 Licq::Event* IcqProtocol::DoneExtendedServerEvent(const unsigned short _nSubSequence, Licq::Event::ResultType _eResult)
1059 {
1060   pthread_mutex_lock(&mutex_extendedevents);
1061   Licq::Event* e = NULL;
1062   list<Licq::Event*>::iterator iter;
1063   for (iter = m_lxExtendedEvents.begin(); iter != m_lxExtendedEvents.end(); ++iter)
1064   {
1065     if ((*iter)->m_nSubSequence == _nSubSequence)
1066     {
1067       e = *iter;
1068       m_lxExtendedEvents.erase(iter);
1069       break;
1070     }
1071   }
1072   pthread_mutex_unlock(&mutex_extendedevents);
1073   if (e != NULL) e->m_eResult = _eResult;
1074   return(e);
1075 }
1076 
1077 
DoneExtendedEvent(Licq::Event * e,Licq::Event::ResultType _eResult)1078 Licq::Event* IcqProtocol::DoneExtendedEvent(Licq::Event* e, Licq::Event::ResultType _eResult)
1079 {
1080   pthread_mutex_lock(&mutex_extendedevents);
1081   list<Licq::Event*>::iterator iter;
1082   for (iter = m_lxExtendedEvents.begin(); iter != m_lxExtendedEvents.end(); ++iter)
1083   {
1084     if (e == (*iter))
1085     {
1086       m_lxExtendedEvents.erase(iter);
1087       break;
1088     }
1089   }
1090   pthread_mutex_unlock(&mutex_extendedevents);
1091   if (iter == m_lxExtendedEvents.end()) return NULL;
1092   e->m_eResult = _eResult;
1093 #if 0
1094   // If the event was cancelled we still want to wait internally for the reply
1095   if (_eResult == Licq::Event::ResultCancelled)
1096   {
1097     pthread_mutex_lock(&mutex_extendedevents);
1098     Licq::Event* e2 = new Licq::Event(e);
1099     e2->m_bCancelled = true;
1100     e2->m_xPacket = e->m_xPacket;
1101     e->m_xPacket = NULL;
1102     m_lxExtendedEvents.push_back(e2);
1103     pthread_mutex_unlock(&mutex_extendedevents);
1104   }
1105 #endif
1106   return(e);
1107 }
1108 
DoneExtendedEvent(unsigned long tag,Licq::Event::ResultType _eResult)1109 Licq::Event* IcqProtocol::DoneExtendedEvent(unsigned long tag, Licq::Event::ResultType _eResult)
1110 {
1111   pthread_mutex_lock(&mutex_extendedevents);
1112   Licq::Event* e = NULL;
1113   list<Licq::Event*>::iterator iter;
1114   for (iter = m_lxExtendedEvents.begin(); iter != m_lxExtendedEvents.end(); ++iter)
1115   {
1116     if ((*iter)->Equals(tag))
1117     {
1118       e = *iter;
1119       m_lxExtendedEvents.erase(iter);
1120       break;
1121     }
1122   }
1123   pthread_mutex_unlock(&mutex_extendedevents);
1124   if (e != NULL) e->m_eResult = _eResult;
1125   return(e);
1126 }
1127 
PushEvent(Licq::Event * e)1128 void IcqProtocol::PushEvent(Licq::Event* e)
1129 {
1130   assert(e != NULL);
1131   pthread_mutex_lock(&mutex_runningevents);
1132   m_lxRunningEvents.push_back(e);
1133   pthread_mutex_unlock(&mutex_runningevents);
1134 }
1135 
1136 /*------------------------------------------------------------------------------
1137  * PushExtendedEvent
1138  *
1139  * Takes the given event, moves it event into the extended event queue.
1140  *----------------------------------------------------------------------------*/
PushExtendedEvent(Licq::Event * e)1141 void IcqProtocol::PushExtendedEvent(Licq::Event* e)
1142 {
1143   assert(e != NULL);
1144   pthread_mutex_lock(&mutex_extendedevents);
1145   m_lxExtendedEvents.push_back(e);
1146 #if 0
1147   gLog.info(tr("%p pushing Command: %d SubCommand: %d Sequence: %hu SubSequence: %d: Uin: %lu"), e,
1148             e->Command(), e->SubCommand(), e->Sequence(), e->SubSequence(), e->Uin());
1149 #endif
1150   pthread_mutex_unlock(&mutex_extendedevents);
1151 }
1152 
1153 //-----CICQDaemon::CancelEvent---------------------------------------------------------
CancelEvent(unsigned long t)1154 void IcqProtocol::CancelEvent(unsigned long t)
1155 {
1156   Licq::Event* eSrv = NULL;
1157   pthread_mutex_lock(&mutex_sendqueue_server);
1158   list<Licq::Event*>::iterator iter;
1159   for (iter = m_lxSendQueue_Server.begin();
1160        iter != m_lxSendQueue_Server.end(); ++iter)
1161   {
1162     if ((*iter)->Equals(t))
1163     {
1164       eSrv = *iter;
1165       m_lxSendQueue_Server.erase(iter);
1166 
1167       Licq::Event* cancelled = new Licq::Event(eSrv);
1168       cancelled->m_bCancelled = true;
1169       m_lxSendQueue_Server.push_back(cancelled);
1170       break;
1171     }
1172   }
1173   pthread_mutex_unlock(&mutex_sendqueue_server);
1174 
1175   Licq::Event* eRun = DoneEvent(t, Licq::Event::ResultCancelled);
1176   Licq::Event* eExt = DoneExtendedEvent(t, Licq::Event::ResultCancelled);
1177 
1178   if (eRun == NULL && eExt == NULL && eSrv == NULL)
1179   {
1180     gLog.warning(tr("Cancelled event not found."));
1181     return;
1182   }
1183 
1184   CancelEvent((eRun != NULL)? eRun : (eExt != NULL)? eExt : eSrv);
1185 }
1186 
CancelEvent(Licq::Event * e)1187 void IcqProtocol::CancelEvent(Licq::Event* e)
1188 {
1189   e->m_eResult = Licq::Event::ResultCancelled;
1190 
1191   if (e->command() == Licq::Event::CommandChatInvite)
1192     icqChatRequestCancel(e->userId(), e->m_nSequence);
1193   else if (e->command() == Licq::Event::CommandFile)
1194     icqFileTransferCancel(e->userId(), e->m_nSequence);
1195   else if (e->command() == Licq::Event::CommandSecureOpen)
1196     icqOpenSecureChannelCancel(e->userId(), e->m_nSequence);
1197 
1198   ProcessDoneEvent(e);
1199 }
1200 
updateAllUsersInGroup(int groupId)1201 void IcqProtocol::updateAllUsersInGroup(int groupId)
1202 {
1203   Licq::UserListGuard userList(myOwnerId);
1204   BOOST_FOREACH(Licq::User* user, **userList)
1205   {
1206     if (groupId != 0)
1207     {
1208       Licq::UserReadGuard u(user);
1209       if (!u->isInGroup(groupId))
1210         continue;
1211     }
1212     icqRequestMetaInfo(user->id());
1213   }
1214 }
1215 
1216 //-----ProcessMessage-----------------------------------------------------------
ProcessMessage(Licq::User * u,CBuffer & packet,const string & message,unsigned short nMsgType,unsigned long nMask,const unsigned long nMsgID[2],unsigned short nSequence,bool bIsAck,bool & bNewUser)1217 void IcqProtocol::ProcessMessage(Licq::User *u, CBuffer &packet, const string& message,
1218     unsigned short nMsgType, unsigned long nMask, const unsigned long nMsgID[2],
1219                                 unsigned short nSequence, bool bIsAck,
1220                                 bool &bNewUser)
1221 {
1222   char *szType = NULL;
1223   Licq::UserEvent* pEvent = NULL;
1224   OnEventData::OnEventType onEventType = OnEventData::OnEventMessage;
1225 
1226   // for acks
1227   unsigned short nPort;
1228 
1229   // Do we accept it if we are in Occ or DND?
1230   // unsigned short nOwnerStatus;
1231   // {
1232   //   Licq::OwnerReadGuard o(myOwnerId);
1233   //   nOwnerStatus = o->Status();
1234   // }
1235 
1236   unsigned short nLevel = nMask;
1237   unsigned long nFlags = ((nMask & ICQ_CMDxSUB_FxMULTIREC) ? (unsigned)Licq::UserEvent::FlagMultiRec : 0)
1238       | ((nMask & ICQ_TCPxMSG_URGENT) ? (unsigned)Licq::UserEvent::FlagUrgent : 0);
1239 
1240   switch (nMsgType)
1241   {
1242   case ICQ_CMDxSUB_MSG:
1243   {
1244     unsigned long fore, back;
1245     packet >> fore >> back;
1246     if (back == fore)
1247     {
1248       back = 0xFFFFFF;
1249       fore = 0x000000;
1250     }
1251 
1252       // Check if message is marked as UTF8
1253       unsigned long guidlen;
1254       packet >> guidlen;
1255       bool isUtf8 = false;
1256       while (guidlen >= 38)
1257       {
1258         string guid = packet.unpackRawString(38);
1259         if (guid == ICQ_CAPABILITY_UTF8_STR)
1260           isUtf8 = true;
1261         guidlen -= 38;
1262       }
1263 
1264       Licq::EventMsg* e = new Licq::EventMsg(
1265           (isUtf8 ? message : Licq::gTranslator.toUtf8(message, u->userEncoding())),
1266           Licq::EventMsg::TimeNow, nFlags);
1267     e->SetColor(fore, back);
1268 
1269     CPU_AckGeneral *p = new CPU_AckGeneral(u, nMsgID[0], nMsgID[1],
1270                                            nSequence, ICQ_CMDxSUB_MSG, true,
1271                                            nLevel);
1272     SendEvent_Server(p);
1273 
1274     szType = strdup(tr("Message"));
1275       onEventType = OnEventData::OnEventMessage;
1276     pEvent = e;
1277     break;
1278   }
1279 
1280     case ICQ_CMDxSUB_CHAT:
1281     {
1282       string chatClients = packet.unpackShortStringLE();
1283     unsigned short nPortReversed;
1284     nPortReversed = packet.UnpackUnsignedShortBE();
1285     packet.incDataPosRead(2);
1286     nPort = packet.UnpackUnsignedShort();
1287 
1288     if (nPort == 0)
1289       nPort = nPortReversed;
1290 
1291     if (!bIsAck)
1292     {
1293         Licq::EventChat* e = new Licq::EventChat(message, chatClients, nPort,
1294             nSequence, Licq::EventChat::TimeNow, nFlags, 0, nMsgID[0], nMsgID[1]);
1295         onEventType = OnEventData::OnEventChat;
1296       pEvent = e;
1297     }
1298 
1299     szType = strdup(tr("Chat request"));
1300     break;
1301   }
1302 
1303   case ICQ_CMDxSUB_FILE:
1304   {
1305     unsigned long nFileSize;
1306 
1307     // Port reversed: garbage when the request is refused
1308     packet.UnpackUnsignedShortBE();
1309 
1310     packet.UnpackUnsignedShort();
1311 
1312       string filename = packet.unpackLongStringLE();
1313       packet >> nFileSize;
1314     if (!bIsAck)
1315     {
1316         list<string> filelist;
1317         filelist.push_back(filename);
1318 
1319         Licq::EventFile* e = new Licq::EventFile(filename,
1320             Licq::gTranslator.fromUtf8(message, u->userEncoding()), nFileSize,
1321             filelist, nSequence, Licq::EventFile::TimeNow, nFlags, 0, nMsgID[0], nMsgID[1]);
1322         onEventType = OnEventData::OnEventFile;
1323       pEvent = e;
1324     }
1325 
1326     packet >> nPort;
1327 
1328     szType = strdup(tr("File transfer request through server"));
1329     break;
1330   }
1331 
1332   case ICQ_CMDxSUB_URL:
1333     {
1334       pEvent = parseUrlEvent(message, Licq::EventUrl::TimeNow, nFlags, u->userEncoding());
1335     CPU_AckGeneral *p = new CPU_AckGeneral(u, nMsgID[0], nMsgID[1],
1336                                            nSequence, ICQ_CMDxSUB_URL, true,
1337                                            nLevel);
1338     SendEvent_Server(p);
1339 
1340     szType = strdup(tr("URL"));
1341       onEventType = OnEventData::OnEventUrl;
1342       break;
1343     }
1344   case ICQ_CMDxSUB_CONTACTxLIST:
1345     {
1346       pEvent = parseContactEvent(message, Licq::EventContactList::TimeNow,
1347           nFlags, u->userEncoding());
1348     CPU_AckGeneral *p = new CPU_AckGeneral(u, nMsgID[0], nMsgID[1],
1349                                            nSequence, ICQ_CMDxSUB_CONTACTxLIST,
1350                                            true, nLevel);
1351     SendEvent_Server(p);
1352 
1353     szType = strdup(tr("Contact list"));
1354       onEventType = OnEventData::OnEventMessage;
1355       break;
1356     }
1357   case ICQ_CMDxTCP_READxNAxMSG:
1358   case ICQ_CMDxTCP_READxDNDxMSG:
1359   case ICQ_CMDxTCP_READxOCCUPIEDxMSG:
1360   case ICQ_CMDxTCP_READxFFCxMSG:
1361   case ICQ_CMDxTCP_READxAWAYxMSG:
1362   {
1363     if (bIsAck)
1364     {
1365         string msgUtf8 = gTranslator.toUtf8(message, u->userEncoding());
1366         if (u->autoResponse() != msgUtf8)
1367         {
1368           u->setAutoResponse(msgUtf8);
1369           u->SetShowAwayMsg(!msgUtf8.empty());
1370           gLog.info(tr("Auto response from %s (#%lu)."), u->getAlias().c_str(), nMsgID[1]);
1371         }
1372         Licq::Event* e = DoneServerEvent(nMsgID[1], Licq::Event::ResultAcked);
1373         if (e)
1374         {
1375           e->m_pExtendedAck = new Licq::ExtendedData(true, 0, msgUtf8);
1376           e->mySubResult = Licq::Event::SubResultReturn;
1377         ProcessDoneEvent(e);
1378       }
1379         else
1380           gLog.warning(tr("Ack for unknown event."));
1381       }
1382       else
1383       {
1384         gLog.info(tr("%s (%s) requested auto response."),
1385             u->getAlias().c_str(), u->accountId().c_str());
1386 
1387     CPU_AckGeneral *p = new CPU_AckGeneral(u, nMsgID[0], nMsgID[1],
1388                                            nSequence, nMsgType, true, nLevel);
1389     SendEvent_Server(p);
1390 
1391         Licq::gStatistics.increase(Licq::Statistics::AutoResponseCheckedCounter);
1392     u->SetLastCheckedAutoResponse();
1393 
1394         Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
1395             Licq::PluginSignal::SignalUser,
1396             Licq::PluginSignal::UserEvents, u->id()));
1397       }
1398     return;
1399 
1400     break; // bah!
1401   }
1402 
1403   case ICQ_CMDxSUB_ICBM:
1404   {
1405     unsigned short nLen;
1406 
1407     packet >> nLen;
1408     packet.incDataPosRead(18);
1409       string plugin = packet.unpackLongStringLE();
1410 
1411       packet.incDataPosRead(nLen - 22 - plugin.size()); // unknown
1412       packet.UnpackUnsignedLong();
1413 
1414     int nCommand = 0;
1415       if (plugin.find("File") != string::npos)
1416       nCommand = ICQ_CMDxSUB_FILE;
1417       else if (plugin.find("URL") != string::npos)
1418       nCommand = ICQ_CMDxSUB_URL;
1419       else if (plugin.find("Chat") != string::npos)
1420       nCommand = ICQ_CMDxSUB_CHAT;
1421       else if (plugin.find("Contacts") != string::npos)
1422       nCommand = ICQ_CMDxSUB_CONTACTxLIST;
1423 
1424     if (nCommand == 0)
1425     {
1426         gLog.warning(tr("Unknown ICBM plugin type: %s"), plugin.c_str());
1427         return;
1428       }
1429 
1430       string msg2 = packet.unpackLongStringLE();
1431 
1432     /* if the auto response is non empty then this is a decline and we want
1433        to show the auto response rather than our original message */
1434 
1435     // recursion
1436       ProcessMessage(u, packet, (message.empty() ? msg2 : message), nCommand,
1437           nMask, nMsgID, nSequence, bIsAck, bNewUser);
1438       return;
1439     }
1440 
1441   default:
1442     szType = strdup(tr("unknown event"));
1443   } // switch nMsgType
1444 
1445   if (bIsAck)
1446   {
1447     Licq::Event* pAckEvent = DoneServerEvent(nMsgID[1], Licq::Event::ResultAcked);
1448     Licq::ExtendedData* pExtendedAck = new Licq::ExtendedData(true, nPort,
1449         gTranslator.toUtf8(message, u->userEncoding()));
1450 
1451     if (pAckEvent)
1452     {
1453       pAckEvent->m_pExtendedAck = pExtendedAck;
1454       pAckEvent->mySubResult = Licq::Event::SubResultAccept;
1455       gLog.info(tr("%s accepted from %s (%s)."), szType,
1456           u->getAlias().c_str(), u->accountId().c_str());
1457       u->unlockWrite();
1458       ProcessDoneEvent(pAckEvent);
1459       u->lockWrite();
1460     }
1461     else
1462     {
1463       gLog.warning(tr("Ack for unknown event."));
1464       delete pExtendedAck;
1465      }
1466   }
1467   else
1468   {
1469     // If it parsed, did it parse properly?
1470     if (pEvent)
1471     {
1472       if (bNewUser)
1473       {
1474         if (gDaemon.ignoreType(Licq::Daemon::IgnoreNewUsers))
1475         {
1476           gLog.info(tr("%s from new user (%s), ignoring."),
1477               szType, u->accountId().c_str());
1478           if (szType)  free(szType);
1479           gDaemon.rejectEvent(u->id(), pEvent);
1480           return;
1481         }
1482         gLog.info(tr("%s from new user (%s)."), szType, u->accountId().c_str());
1483 
1484         // Don't delete user when we're done
1485         bNewUser = false;
1486       }
1487       else
1488         gLog.info(tr("%s from %s (%s)."), szType, u->getAlias().c_str(),
1489             u->accountId().c_str());
1490 
1491       if (gDaemon.addUserEvent(u, pEvent))
1492         gOnEventManager.performOnEvent(onEventType, u);
1493     }
1494     else // invalid parse or unknown event
1495     {
1496       packet.log(Licq::Log::Warning, tr("Invalid %s"), szType);
1497     }
1498   }
1499 
1500   if (szType)  free(szType);
1501 }
1502 
processServerMessage(int type,Licq::Buffer & packet,const Licq::UserId & userId,string & message,time_t timeSent,unsigned long flags)1503 void IcqProtocol::processServerMessage(int type, Licq::Buffer &packet,
1504     const Licq::UserId& userId, string& message, time_t timeSent,
1505     unsigned long flags)
1506 {
1507   if (type & ICQ_CMDxSUB_FxMULTIREC)
1508   {
1509     flags |= Licq::UserEvent::FlagMultiRec;
1510     type &= ~ICQ_CMDxSUB_FxMULTIREC;
1511   }
1512 
1513   // Drop trailing nul characters from message
1514   while (message.size() > 0 && message[message.size()-1] == '\0')
1515     message.resize(message.size()-1);
1516 
1517   string userEncoding = getUserEncoding(userId);
1518 
1519   OnEventData::OnEventType onEventType = OnEventData::OnEventMessage;
1520   Licq::UserEvent* ue;
1521 
1522   switch (type)
1523   {
1524     case ICQ_CMDxSUB_MSG:
1525     {
1526       onEventType = OnEventData::OnEventMessage;
1527       ue = new Licq::EventMsg(
1528           gTranslator.toUtf8(gTranslator.returnToUnix(message), userEncoding),
1529           timeSent, flags);
1530       break;
1531     }
1532     case ICQ_CMDxSUB_URL:
1533     {
1534       onEventType = OnEventData::OnEventUrl;
1535       ue = parseUrlEvent(message, timeSent, flags, userEncoding);
1536       if (ue == NULL)
1537       {
1538         packet.log(Log::Warning, tr("Invalid URL message"));
1539         return;
1540       }
1541       break;
1542     }
1543     case ICQ_CMDxSUB_AUTHxREQUEST:
1544     {
1545       gLog.info(tr("Authorization request from %s"), userId.toString().c_str());
1546 
1547       vector<string> parts; // alias, first name, last name, email, auth, comment
1548       splitFE(parts, message, 6, userEncoding);
1549       if (parts.size() != 6)
1550       {
1551         packet.log(Log::Warning, tr("Invalid authorization request system message"));
1552         return;
1553       }
1554 
1555       ue = new Licq::EventAuthRequest(userId, parts.at(0), parts.at(1), parts.at(2),
1556           parts.at(3), gTranslator.returnToUnix(parts.at(5)), timeSent, flags);
1557       break;
1558     }
1559     case ICQ_CMDxSUB_AUTHxREFUSED:  // system message: authorization refused
1560     {
1561       gLog.info(tr("Authorization refused by %s"), userId.toString().c_str());
1562       ue = new Licq::EventAuthRefused(userId,
1563           gTranslator.returnToUnix(gTranslator.toUtf8(message, userEncoding)),
1564           timeSent, flags);
1565       break;
1566     }
1567     case ICQ_CMDxSUB_AUTHxGRANTED:  // system message: authorized
1568     {
1569       gLog.info(tr("Authorization granted by %s"), userId.toString().c_str());
1570 
1571       {
1572         Licq::UserWriteGuard u(userId);
1573         if (u.isLocked())
1574           u->SetAwaitingAuth(false);
1575       }
1576 
1577       ue = new Licq::EventAuthGranted(userId,
1578           gTranslator.returnToUnix(gTranslator.toUtf8(message, userEncoding)),
1579           timeSent, flags);
1580       break;
1581     }
1582     case ICQ_CMDxSUB_MSGxSERVER:
1583     {
1584       gLog.info(tr("Server message."));
1585 
1586       vector<string> parts;
1587       splitFE(parts, message, 6, userEncoding);
1588       if (parts.size() != 6)
1589       {
1590         packet.log(Log::Warning, tr("Invalid Server Message"));
1591         return;
1592       }
1593 
1594       ue = new Licq::EventServerMessage(parts.at(0), parts.at(3),
1595           gTranslator.returnToUnix(parts.at(5)), timeSent);
1596       break;
1597     }
1598     case ICQ_CMDxSUB_ADDEDxTOxLIST:  // system message: added to a contact list
1599     {
1600       gLog.info(tr("User %s added you to their contact list"), userId.toString().c_str());
1601 
1602       vector<string> parts; // alias, first name, last name, email, auth, comment
1603       splitFE(parts, message, 6, userEncoding);
1604       if (parts.size() != 6)
1605       {
1606         packet.log(Log::Warning, tr("Invalid added to list system message"));
1607         return;
1608       }
1609 
1610       ue = new Licq::EventAdded(userId, parts.at(0), parts.at(1), parts.at(2),
1611           parts.at(3), timeSent, flags);
1612       break;
1613     }
1614     case ICQ_CMDxSUB_WEBxPANEL:
1615     {
1616       gLog.info(tr("Message through web panel"));
1617 
1618       vector<string> parts; // name, ?, ?, email, ?, message
1619       splitFE(parts, message, 6, userEncoding);
1620       if (parts.size() != 6)
1621       {
1622         packet.log(Log::Warning, tr("Invalid web panel system message"));
1623         return;
1624       }
1625 
1626       gLog.info(tr("From %s (%s)"), parts.at(0).c_str(), parts.at(3).c_str());
1627       ue = new Licq::EventWebPanel(parts.at(0), parts.at(3),
1628           gTranslator.returnToUnix(parts.at(5)), timeSent, flags);
1629       break;
1630     }
1631     case ICQ_CMDxSUB_EMAILxPAGER:
1632     {
1633       gLog.info(tr("Email pager message"));
1634 
1635       vector<string> parts; // name, ?, ?, email, ?, message
1636       splitFE(parts, message, 6, userEncoding);
1637       if (parts.size() != 6)
1638       {
1639         packet.log(Log::Warning, tr("Invalid email pager system message"));
1640         return;
1641       }
1642 
1643       gLog.info(tr("From %s (%s)"), parts.at(0).c_str(), parts.at(3).c_str());
1644       ue = new Licq::EventEmailPager(parts.at(0), parts.at(3),
1645           gTranslator.returnToUnix(parts.at(5)), timeSent, flags);
1646       break;
1647     }
1648     case ICQ_CMDxSUB_CONTACTxLIST:
1649     {
1650       onEventType = OnEventData::OnEventMessage;
1651       ue = parseContactEvent(message, timeSent, flags, userEncoding);
1652       if (ue == NULL)
1653       {
1654         packet.log(Log::Warning, tr("Invalid Contact List message"));
1655         return;
1656       }
1657       break;
1658     }
1659     case ICQ_CMDxSUB_SMS:
1660     {
1661       string xmlSms = getXmlTag(message, "sms_message");
1662       if (xmlSms.empty())
1663       {
1664         packet.log(Log::Warning, tr("Invalid SMS message"));
1665         return;
1666       }
1667 
1668       string number = getXmlTag(xmlSms, "sender");
1669       string msg = getXmlTag(xmlSms, "text");
1670 
1671       ue = new Licq::EventSms(number, msg, timeSent, flags);
1672       break;
1673     }
1674     default:
1675     {
1676       size_t pos = 0;
1677       while ((pos = message.find('\xFE')) != string::npos)
1678         message[pos] = '\n';
1679 
1680       packet.log(Log::Unknown, "Unknown system message (0x%04x)", type);
1681       ue = new Licq::EventUnknownSysMsg(type,
1682             ICQ_CMDxRCV_SYSxMSGxOFFLINE, userId, message, timeSent, 0);
1683       break;
1684     }
1685   }
1686 
1687   switch (type)
1688   {
1689     case ICQ_CMDxSUB_MSG:
1690     case ICQ_CMDxSUB_URL:
1691     case ICQ_CMDxSUB_CONTACTxLIST:
1692     {
1693       // Get the user and allow adding unless we ignore new users
1694       Licq::UserWriteGuard u(userId, !gDaemon.ignoreType(Daemon::IgnoreNewUsers));
1695       if (!u.isLocked())
1696       {
1697         gLog.info(tr("%s from new user (%s), ignoring"),
1698             ue->description().c_str(), userId.toString().c_str());
1699         gDaemon.rejectEvent(userId, ue);
1700         break;
1701       }
1702       else
1703         gLog.info(tr("%s through server from %s (%s)"),
1704             ue->description().c_str(), u->getAlias().c_str(), userId.toString().c_str());
1705 
1706       u->setIsTyping(false);
1707 
1708       if (gDaemon.addUserEvent(*u, ue))
1709         gOnEventManager.performOnEvent(onEventType, *u);
1710 
1711       gPluginManager.pushPluginSignal(new Licq::PluginSignal(
1712           Licq::PluginSignal::SignalUser, Licq::PluginSignal::UserTyping, u->id()));
1713 
1714       break;
1715     }
1716     case ICQ_CMDxSUB_AUTHxREQUEST:
1717     case ICQ_CMDxSUB_AUTHxREFUSED:
1718     case ICQ_CMDxSUB_AUTHxGRANTED:
1719     case ICQ_CMDxSUB_MSGxSERVER:
1720     case ICQ_CMDxSUB_ADDEDxTOxLIST:
1721     case ICQ_CMDxSUB_WEBxPANEL:
1722     case ICQ_CMDxSUB_EMAILxPAGER:
1723     {
1724       bool bIgnore;
1725       {
1726         Licq::UserReadGuard u(userId);
1727         bIgnore = (u.isLocked() && u->IgnoreList());
1728       }
1729 
1730       if (bIgnore)
1731       {
1732         delete ue; // Processing stops here, needs to be deleted
1733         gLog.info(tr("Ignored!"));
1734         break;
1735       }
1736 
1737       Licq::OwnerWriteGuard o(myOwnerId);
1738       if (gDaemon.addUserEvent(*o, ue))
1739       {
1740         ue->AddToHistory(*o, true);
1741         gOnEventManager.performOnEvent(OnEventData::OnEventSysMsg, *o);
1742       }
1743       break;
1744     }
1745 
1746     case ICQ_CMDxSUB_SMS:
1747     {
1748       Licq::EventSms* eSms = dynamic_cast<Licq::EventSms*>(ue);
1749       string idSms = findUserByCellular(eSms->number());
1750 
1751       if (!idSms.empty())
1752       {
1753         Licq::UserWriteGuard u(Licq::UserId(myOwnerId, idSms.c_str()));
1754         gLog.info(tr("SMS from %s - %s (%s)"), eSms->number().c_str(),
1755             u->getAlias().c_str(), idSms.c_str());
1756         gDaemon.addUserEvent(*u, ue);
1757       }
1758       else
1759       {
1760         Licq::OwnerWriteGuard o(myOwnerId);
1761         gLog.info(tr("SMS from %s."), eSms->number().c_str());
1762         if (gDaemon.addUserEvent(*o, ue))
1763         {
1764           ue->AddToHistory(*o, true);
1765         }
1766       }
1767       break;
1768     }
1769     default:
1770     {
1771       Licq::OwnerWriteGuard o(myOwnerId);
1772       gDaemon.addUserEvent(*o, ue);
1773     }
1774   }
1775 }
1776 
waitForReverseConnection(unsigned short id,const Licq::UserId & userId)1777 bool IcqProtocol::waitForReverseConnection(unsigned short id, const Licq::UserId& userId)
1778 {
1779   bool bSuccess = false;
1780   pthread_mutex_lock(&mutex_reverseconnect);
1781 
1782   std::list<CReverseConnectToUserData *>::iterator iter;
1783   for (iter = m_lReverseConnect.begin(); iter != m_lReverseConnect.end();
1784     ++iter)
1785   {
1786     if ((*iter)->nId == id && (*iter)->myIdString == userId.accountId())
1787       break;
1788   }
1789 
1790   if (iter == m_lReverseConnect.end())
1791   {
1792     gLog.warning(tr("Failed to find desired connection record."));
1793     goto done;
1794   }
1795 
1796   struct timespec ts;
1797   ts.tv_nsec = 0;
1798   //wait for 30 seconds
1799   ts.tv_sec = time(NULL) + 30;
1800 
1801   while (pthread_cond_timedwait(&cond_reverseconnect_done,
1802     &mutex_reverseconnect, &ts) == 0)
1803   {
1804     for (iter = m_lReverseConnect.begin(); ; ++iter)
1805     {
1806       if (iter == m_lReverseConnect.end())
1807       {
1808         gLog.warning(tr("Somebody else removed our connection record."));
1809         goto done;
1810       }
1811       if ((*iter)->nId == id && (*iter)->myIdString == userId.accountId())
1812       {
1813         if ((*iter)->bFinished)
1814         {
1815           bSuccess = (*iter)->bSuccess;
1816           delete *iter;
1817           m_lReverseConnect.erase(iter);
1818           goto done;
1819         }
1820         break;
1821       }
1822     }
1823   }
1824 
1825   // timed out, just remove the record
1826   for (iter = m_lReverseConnect.begin(); iter != m_lReverseConnect.end();
1827     ++iter)
1828   {
1829     if ((*iter)->nId == id && (*iter)->myIdString == userId.accountId())
1830     {
1831       delete *iter;
1832       m_lReverseConnect.erase(iter);
1833       break;
1834     }
1835   }
1836 
1837 done:
1838   pthread_mutex_unlock(&mutex_reverseconnect);
1839   return bSuccess;
1840 }
1841 
getXmlTag(const string & xmlSource,const string & tagName)1842 string IcqProtocol::getXmlTag(const string& xmlSource, const string& tagName)
1843 {
1844   size_t startPos = xmlSource.find("<" + tagName + ">");
1845   size_t endPos = xmlSource.find("</" + tagName + ">");
1846   if (startPos == string::npos || endPos == string::npos)
1847     return "";
1848   startPos += tagName.size() + 2;
1849   if (startPos > endPos)
1850     return "";
1851   return xmlSource.substr(startPos, endPos - startPos);
1852 }
1853 
icqStatusFromStatus(unsigned status)1854 unsigned short IcqProtocol::icqStatusFromStatus(unsigned status)
1855 {
1856   if (status == Licq::User::OfflineStatus)
1857     return ICQ_STATUS_OFFLINE;
1858 
1859   unsigned short icqStatus;
1860   if (status & Licq::User::DoNotDisturbStatus)
1861     icqStatus = ICQ_STATUS_DND | ICQ_STATUS_AWAY | ICQ_STATUS_OCCUPIED;
1862   else if (status & Licq::User::OccupiedStatus)
1863     icqStatus = ICQ_STATUS_OCCUPIED | ICQ_STATUS_AWAY;
1864   else if (status & Licq::User::NotAvailableStatus)
1865     icqStatus = ICQ_STATUS_NA | ICQ_STATUS_AWAY;
1866   else if (status & Licq::User::AwayStatus)
1867     icqStatus = ICQ_STATUS_AWAY;
1868   else if (status & Licq::User::FreeForChatStatus)
1869     icqStatus = ICQ_STATUS_FREEFORCHAT;
1870   else
1871     icqStatus = ICQ_STATUS_ONLINE;
1872 
1873   if (status & Licq::User::InvisibleStatus)
1874     icqStatus |= ICQ_STATUS_FxPRIVATE;
1875 
1876   return icqStatus;
1877 }
1878 
statusFromIcqStatus(unsigned short icqStatus)1879 unsigned IcqProtocol::statusFromIcqStatus(unsigned short icqStatus)
1880 {
1881   // Build status from ICQ flags
1882   if (icqStatus == ICQ_STATUS_OFFLINE)
1883     return Licq::User::OfflineStatus;
1884 
1885   unsigned status = Licq::User::OnlineStatus;
1886   if (icqStatus & ICQ_STATUS_FxPRIVATE)
1887     status |= Licq::User::InvisibleStatus;
1888   if (icqStatus & ICQ_STATUS_DND)
1889     status |= Licq::User::DoNotDisturbStatus;
1890   else if (icqStatus & ICQ_STATUS_OCCUPIED)
1891     status |= Licq::User::OccupiedStatus;
1892   else if (icqStatus & ICQ_STATUS_NA)
1893     status |= Licq::User::NotAvailableStatus;
1894   else if (icqStatus & ICQ_STATUS_AWAY)
1895     status |= Licq::User::AwayStatus;
1896   if (icqStatus & ICQ_STATUS_FREEFORCHAT)
1897     status |= Licq::User::FreeForChatStatus;
1898 
1899   return status;
1900 }
1901 
addStatusFlags(unsigned long s,const User * u)1902 unsigned long IcqProtocol::addStatusFlags(unsigned long s, const User* u)
1903 {
1904   s &= 0x0000FFFF;
1905 
1906   if (u->webPresence())
1907     s |= ICQ_STATUS_FxWEBxPRESENCE;
1908   if (u->hideIp())
1909     s |= ICQ_STATUS_FxHIDExIP;
1910   if (u->birthdayFlag())
1911     s |= ICQ_STATUS_FxBIRTHDAY;
1912   if (u->homepageFlag())
1913     s |= ICQ_STATUS_FxICQxHOMEPAGE;
1914 
1915   if (u->phoneFollowMeStatus() != IcqPluginInactive)
1916     s |= ICQ_STATUS_FxPFM;
1917   if (u->phoneFollowMeStatus() == IcqPluginActive)
1918     s |= ICQ_STATUS_FxPFMxAVAILABLE;
1919 
1920   switch (u->directFlag())
1921   {
1922     case User::DirectDisabled:
1923       s |= ICQ_STATUS_FxDIRECTxDISABLED;
1924       break;
1925     case User::DirectListed:
1926       s |= ICQ_STATUS_FxDIRECTxLISTED;
1927       break;
1928     case User::DirectAuth:
1929       s |= ICQ_STATUS_FxDIRECTxAUTH;
1930       break;
1931   }
1932 
1933   return s;
1934 }
1935 
getUserEncoding(const Licq::UserId & userId)1936 string IcqProtocol::getUserEncoding(const Licq::UserId& userId)
1937 {
1938   Licq::UserReadGuard u(userId);
1939   if (u.isLocked())
1940     return u->userEncoding();
1941   else
1942     return Licq::gUserManager.defaultUserEncoding();
1943 }
1944 
UseServerContactList() const1945 bool IcqProtocol::UseServerContactList() const
1946 {
1947   OwnerReadGuard o(myOwnerId);
1948   return o->useServerContactList();
1949 }
1950 
getGroupFromId(unsigned short gsid)1951 int IcqProtocol::getGroupFromId(unsigned short gsid)
1952 {
1953   return Licq::gUserManager.getGroupFromServerId(myOwnerId, gsid);
1954 }
1955 
icqOwnerUin()1956 unsigned long IcqProtocol::icqOwnerUin()
1957 {
1958   return strtoul(myOwnerId.accountId().c_str(), (char**)NULL, 10);
1959 }
1960 
generateSid()1961 unsigned short IcqProtocol::generateSid()
1962 {
1963   unsigned short ownerPDINFO;
1964   {
1965     OwnerReadGuard o(myOwnerId);
1966     ownerPDINFO = o->GetPDINFO();
1967   }
1968 
1969   // Generate a SID
1970   srand(time(NULL));
1971   int sid = 1+(int)(65535.0*rand()/(RAND_MAX+1.0));
1972 
1973   sid &= 0x7FFF; // server limit it looks like
1974 
1975   // Make sure we have a unique number - a map would be better
1976   bool done;
1977   do
1978   {
1979     done = true;
1980     bool checkGroup = true;
1981 
1982     if (sid == 0)
1983       ++sid;
1984     if (sid == ownerPDINFO)
1985       sid++;
1986 
1987     {
1988       Licq::UserListGuard userList(myOwnerId);
1989       BOOST_FOREACH(const Licq::User* user, **userList)
1990       {
1991         UserReadGuard u(dynamic_cast<const User*>(user));
1992 
1993         if (u->GetSID() == sid || u->GetInvisibleSID() == sid ||
1994           u->GetVisibleSID() == sid)
1995         {
1996           if (sid == 0x7FFF)
1997             sid = 1;
1998           else
1999             ++sid;
2000           done = false;	// Restart
2001           checkGroup = false;	// Don't waste time now
2002           break;
2003         }
2004       }
2005     }
2006 
2007     if (checkGroup)
2008     {
2009       // Check our groups too!
2010       Licq::GroupListGuard groupList;
2011       BOOST_FOREACH(const Licq::Group* group, **groupList)
2012       {
2013         Licq::GroupReadGuard g(group);
2014 
2015         unsigned short icqGroupId = g->serverId(myOwnerId);
2016         if (icqGroupId == sid)
2017         {
2018           if (sid == 0x7FFF)
2019             sid = 1;
2020           else
2021             ++sid;
2022           done = false;
2023           break;
2024         }
2025       }
2026     }
2027 
2028   } while (!done);
2029 
2030   return sid;
2031 }
2032 
splitFE(vector<string> & ret,const string & s,int maxcount,const string & userEncoding)2033 void IcqProtocol::splitFE(vector<string>& ret, const string& s, int maxcount,
2034     const string& userEncoding)
2035 {
2036   size_t pos = 0;
2037   while (maxcount == 0 || maxcount > 1)
2038   {
2039     size_t pos2 = s.find('\xFE', pos);
2040     if (pos2 == string::npos)
2041       break;
2042 
2043     ret.push_back(gTranslator.toUtf8(s.substr(pos, pos2-pos), userEncoding));
2044     if (maxcount > 0)
2045       maxcount--;
2046     pos = pos2 + 1;
2047   }
2048 
2049   ret.push_back(gTranslator.toUtf8(s.substr(pos), userEncoding));
2050 }
2051 
parseUrlEvent(const string & s,time_t timeSent,unsigned long flags,const string & userEncoding)2052 Licq::EventUrl* IcqProtocol::parseUrlEvent(const string& s, time_t timeSent,
2053     unsigned long flags, const string& userEncoding)
2054 {
2055   vector<string> parts;
2056   splitFE(parts, s, 2, userEncoding);
2057   if (parts.size() < 2)
2058     return NULL;
2059 
2060   // Part 0 is URL, part 1 is description
2061   return new Licq::EventUrl(gTranslator.returnToUnix(parts.at(1)),
2062       parts.at(0), timeSent, flags);
2063 }
2064 
parseContactEvent(const string & s,time_t timeSent,unsigned long flags,const string & userEncoding)2065 Licq::EventContactList* IcqProtocol::parseContactEvent(const string& s,
2066     time_t timeSent, unsigned long flags, const string& userEncoding)
2067 {
2068   vector<string> parts;
2069   splitFE(parts, s, 0, userEncoding);
2070 
2071   // First part is number of contacts in the list
2072   size_t count = atoi(parts.at(0).c_str());
2073   if (parts.size() < count*2+2)
2074     return NULL;
2075 
2076   Licq::EventContactList::ContactList vc;
2077   for (size_t i = 0; i < count; ++i)
2078   {
2079     Licq::UserId userId(myOwnerId, parts.at(i*2+1));
2080     vc.push_back(new Licq::EventContactList::Contact(userId, parts.at(i*2+2)));
2081   }
2082 
2083   return new Licq::EventContactList(vc, false, timeSent, flags);
2084 }
2085 
CReverseConnectToUserData(const char * idString,unsigned long id,unsigned long data,unsigned long ip,unsigned short port,unsigned short version,unsigned short failedport,unsigned long msgid1,unsigned long msgid2)2086 CReverseConnectToUserData::CReverseConnectToUserData(const char* idString, unsigned long id,
2087       unsigned long data, unsigned long ip, unsigned short port,
2088       unsigned short version, unsigned short failedport, unsigned long msgid1,
2089       unsigned long msgid2) :
2090   myIdString(idString), nId(id), nData(data), nIp(ip), nPort(port),
2091   nFailedPort(failedport), nVersion(version), nMsgID1(msgid1),
2092   nMsgID2(msgid2), bSuccess(false), bFinished(false)
2093 {
2094   // Empty
2095 }
2096 
~CReverseConnectToUserData()2097 CReverseConnectToUserData::~CReverseConnectToUserData()
2098 {
2099   // Empty
2100 }
2101 
CUserProperties()2102 CUserProperties::CUserProperties()
2103   : normalSid(0),
2104     groupId(0),
2105     visibleSid(0),
2106     invisibleSid(0),
2107     inIgnoreList(false),
2108     awaitingAuth(false)
2109 {
2110   tlvs.clear();
2111 }
2112