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