1 /*
2 * This file is part of Licq, an instant messaging client for UNIX.
3 * Copyright (C) 2004-2013 Licq developers <licq-dev@googlegroups.com>
4 *
5 * Licq is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * Licq is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Licq; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "msn.h"
21 #include "msnpacket.h"
22 #include <licq/logging/log.h>
23
24 #include <boost/foreach.hpp>
25 #include <cassert>
26 #include <cstdio>
27 #include <string>
28 #include <list>
29 #include <unistd.h>
30 #include <vector>
31
32 #include <licq/contactlist/usermanager.h>
33 #include <licq/crypto.h>
34 #include <licq/daemon.h>
35 #include <licq/event.h>
36 #include <licq/logging/logservice.h>
37 #include <licq/oneventmanager.h>
38 #include <licq/plugin/pluginmanager.h>
39 #include <licq/pluginsignal.h>
40 #include <licq/socket.h>
41 #include <licq/userevents.h>
42
43 #include "owner.h"
44 #include "user.h"
45
46 using namespace LicqMsn;
47 using Licq::OnEventData;
48 using Licq::UserId;
49 using Licq::gLog;
50 using Licq::gOnEventManager;
51 using Licq::gUserManager;
52 using std::string;
53
ProcessServerPacket(CMSNBuffer * packet)54 void CMSN::ProcessServerPacket(CMSNBuffer *packet)
55 {
56 CMSNPacket *pReply;
57
58 //while (!m_pPacketBuf->End())
59 {
60 pReply = 0;
61 string strCmd = packet->unpackRawString(3);
62
63 if (strCmd == "VER")
64 {
65 // Don't really care about this packet's data.
66 pReply = new CPS_MSNClientVersion(myOwnerId.accountId());
67 }
68 else if (strCmd == "CVR")
69 {
70 // Don't really care about this packet's data.
71 pReply = new CPS_MSNUser(myOwnerId.accountId());
72 }
73 else if (strCmd == "XFR")
74 {
75 //Time to transfer to a new server
76 packet->SkipParameter(); // Seq
77 string strServType = packet->GetParameter();
78 string strServer = packet->GetParameter();
79
80 if (strServType == "SB")
81 {
82 packet->SkipParameter(); // 'CKI'
83 string strCookie = packet->GetParameter();
84
85 MSNSBConnectStart(strServer, strCookie);
86 }
87 else
88 {
89 size_t sep = strServer.rfind(':');
90 string host;
91 int port = 0;
92 if (sep != string::npos)
93 {
94 host = strServer.substr(0, sep);
95 port = atoi(strServer.substr(sep+1).c_str());
96 }
97
98 closeSocket(myServerSocket, false);
99 myServerSocket = NULL;
100
101 // Make the new connection
102 Logon(myOwnerId, myStatus, host.c_str(), port);
103 }
104 }
105 else if (strCmd == "USR")
106 {
107 packet->SkipParameter(); // Seq
108 string strType = packet->GetParameter();
109
110 if (strType == "OK")
111 {
112 packet->SkipParameter(); // email account
113 string strNick = packet->GetParameter();
114 string strDecodedNick = Decode(strNick);
115 gLog.info("%s logged in", strDecodedNick.c_str());
116
117 // Set our alias here
118 unsigned long listVersion;
119 {
120 OwnerWriteGuard o(myOwnerId);
121 o->setAlias(strDecodedNick);
122 listVersion = o->listVersion();
123 }
124
125 // This cookie doesn't work anymore now that we are online
126 myCookie.clear();
127
128 pReply = new CPS_MSNSync(listVersion);
129 }
130 else
131 {
132 packet->SkipParameter(); // "S"
133 myCookie = packet->GetParameter();
134
135 // Make an SSL connection to authenticate
136 MSNAuthenticate();
137 }
138 }
139 else if (strCmd == "CHL")
140 {
141 packet->SkipParameter(); // Seq
142 string strHash = packet->GetParameter();
143
144 pReply = new CPS_MSNChallenge(strHash);
145 }
146 else if (strCmd == "SYN")
147 {
148 packet->SkipParameter();
149 string strVersion = packet->GetParameter();
150 unsigned long newListVersion = atol(strVersion.c_str());
151 {
152 OwnerWriteGuard o(myOwnerId);
153 o->setListVersion(newListVersion);
154 }
155
156 MSNChangeStatus(myStatus);
157
158 // Send our local list now
159 //Licq::UserListGuard userList(myOwnerId);
160 //BOOST_FOREACH(const Licq::User* user, **userList)
161 //{
162 // pReply = new CPS_MSNAddUser(user->accountId());
163 // SendPacket(pReply);
164 //}
165 }
166 else if (strCmd == "LST")
167 {
168 // Add user
169 string strUser = packet->GetParameter();
170 UserId userId(myOwnerId, strUser);
171 string strNick = packet->GetParameter();
172 string strLists = packet->GetParameter();
173 string strUserLists;
174
175 if (userId == myOwnerId)
176 return;
177
178 int nLists = atoi(strLists.c_str());
179 if (nLists & FLAG_CONTACT_LIST)
180 strUserLists = packet->GetParameter();
181
182 if (nLists & FLAG_CONTACT_LIST)
183 gUserManager.addUser(userId, true, false);
184
185 Licq::UserWriteGuard u(userId);
186 if (u.isLocked())
187 {
188 u->SetEnableSave(false);
189 u->setUserEncoding("UTF-8");
190 u->SetInvisibleList(nLists & FLAG_BLOCK_LIST);
191
192 if (!u->KeepAliasOnUpdate())
193 {
194 string strDecodedNick = Decode(strNick);
195 u->setAlias(strDecodedNick);
196 Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
197 Licq::PluginSignal::SignalUser,
198 Licq::PluginSignal::UserBasic, u->id()));
199 }
200 u->setUserInfoString("Email1", strUser);
201 string strURL = "http://members.msn.com/"+strUser;
202 u->setUserInfoString("Homepage", strURL);
203 u->SetNewUser(false);
204 u->SetEnableSave(true);
205 u->save(Licq::User::SaveLicqInfo);
206 Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
207 Licq::PluginSignal::SignalUser,
208 Licq::PluginSignal::UserInfo, u->id()));
209 }
210 }
211 else if (strCmd == "LSG")
212 {
213 // Add group
214 }
215 else if (strCmd == "ADD")
216 {
217 packet->SkipParameter(); // What's this?
218 string strList = packet->GetParameter();
219 string strVersion = packet->GetParameter();
220 string strUser = packet->GetParameter();
221 UserId userId(myOwnerId, strUser);
222 string strNick = packet->GetParameter();
223
224 unsigned long newListVersion = atol(strVersion.c_str());
225 {
226 OwnerWriteGuard o(myOwnerId);
227 o->setListVersion(newListVersion);
228 }
229
230 if (strList == "RL")
231 {
232 gLog.info("Authorization request from %s", strUser.c_str());
233
234 Licq::UserEvent* e = new Licq::EventAuthRequest(userId,
235 strNick.c_str(), "", "", "", "", time(0), 0);
236
237 Licq::OwnerWriteGuard o(myOwnerId);
238 if (Licq::gDaemon.addUserEvent(*o, e))
239 {
240 e->AddToHistory(*o, true);
241 gOnEventManager.performOnEvent(OnEventData::OnEventSysMsg, *o);
242 }
243 }
244 else
245 {
246 gLog.info("Added %s to contact list", strUser.c_str());
247
248 Licq::UserWriteGuard u(userId);
249 if (u.isLocked())
250 {
251 if (!u->KeepAliasOnUpdate())
252 {
253 string strDecodedNick = Decode(strNick);
254 u->setAlias(strDecodedNick);
255 }
256 Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
257 Licq::PluginSignal::SignalUser,
258 Licq::PluginSignal::UserBasic, u->id()));
259 }
260 }
261 }
262 else if (strCmd == "REM")
263 {
264 packet->SkipParameter(); // seq
265 packet->SkipParameter(); // list
266 string strVersion = packet->GetParameter();
267 string strUser = packet->GetParameter();
268
269 unsigned long newListVersion = atol(strVersion.c_str());
270 {
271 OwnerWriteGuard o(myOwnerId);
272 o->setListVersion(newListVersion);
273 }
274
275 gLog.info("Removed %s from contact list", strUser.c_str());
276 }
277 else if (strCmd == "REA")
278 {
279 packet->SkipParameter(); // seq
280 string strVersion = packet->GetParameter();
281 string strUser = packet->GetParameter();
282 string strNick = packet->GetParameter();
283
284 unsigned long newListVersion = atol(strVersion.c_str());
285 {
286 OwnerWriteGuard o(myOwnerId);
287 o->setListVersion(newListVersion);
288 }
289
290 if (strUser == myOwnerId.accountId())
291 {
292 Licq::OwnerWriteGuard o(myOwnerId);
293 string strDecodedNick = Decode(strNick);
294 o->setAlias(strDecodedNick);
295 }
296
297 gLog.info("%s renamed successfully", strUser.c_str());
298 }
299 else if (strCmd == "CHG")
300 {
301 packet->SkipParameter(); // seq
302 string strStatus = packet->GetParameter();
303 unsigned status;
304
305 if (strStatus == "NLN")
306 status = User::OnlineStatus;
307 else if (strStatus == "BSY")
308 status = User::OnlineStatus | User::OccupiedStatus;
309 else if (strStatus == "HDN")
310 status = User::OnlineStatus | User::InvisibleStatus;
311 else if (strStatus == "IDL")
312 status = User::OnlineStatus | User::IdleStatus;
313 else
314 status = User::OnlineStatus | User::AwayStatus;
315
316 gLog.info("Server says we are now: %s",
317 User::statusToString(status, true, false).c_str());
318 myStatus = status;
319
320 Licq::OwnerWriteGuard o(myOwnerId);
321 if (o.isLocked())
322 o->statusChanged(status);
323 }
324 else if (strCmd == "ILN" || strCmd == "NLN")
325 {
326 if (strCmd == "ILN")
327 packet->SkipParameter(); // seq
328 string strStatus = packet->GetParameter();
329 Licq::UserId userId(myOwnerId, packet->GetParameter());
330 string strNick = packet->GetParameter();
331 string strClientId = packet->GetParameter();
332 string strMSNObject = packet->GetParameter();
333 string strDecodedObject = strMSNObject.size() ? Decode(strMSNObject) :"";
334
335 unsigned status;
336 if (strStatus == "NLN")
337 status = User::OnlineStatus;
338 else if (strStatus == "BSY")
339 status = User::OnlineStatus | User::OccupiedStatus;
340 else if (strStatus == "IDL")
341 status = User::OnlineStatus | User::IdleStatus;
342 else
343 status = User::OnlineStatus | User::AwayStatus;
344
345 UserWriteGuard u(userId);
346 if (u.isLocked())
347 {
348 u->SetSendServer(true); // no direct connections
349
350 if (!u->KeepAliasOnUpdate())
351 {
352 string strDecodedNick = Decode(strNick);
353 u->setAlias(strDecodedNick);
354 Licq::gPluginManager.pushPluginSignal(new Licq::PluginSignal(
355 Licq::PluginSignal::SignalUser,
356 Licq::PluginSignal::UserBasic, u->id()));
357 }
358
359 // Get the display picture here, so it can be shown with the notify
360 if (strDecodedObject != u->pictureObject())
361 {
362 // TODO: User shouldn't be updated until the new picture is actually received
363 u->setPictureObject(strDecodedObject);
364 if (strDecodedObject.size())
365 MSNGetDisplayPicture(u->id(), strDecodedObject);
366 }
367
368 gLog.info("%s changed status (%s)", u->getAlias().c_str(), strStatus.c_str());
369 u->statusChanged(status);
370 }
371 }
372 else if (strCmd == "FLN")
373 {
374 UserId userId(myOwnerId, packet->GetParameter());
375
376 {
377 Licq::UserWriteGuard u(userId);
378 if (u.isLocked())
379 {
380 gLog.info("%s logged off", u->getAlias().c_str());
381 u->statusChanged(User::OfflineStatus);
382 }
383 }
384
385 // Do we have a connection attempt to this user?
386 StartList::iterator it;
387 for (it = m_lStart.begin(); it != m_lStart.end(); it++)
388 {
389 if (*it && userId == (*it)->userId)
390 {
391 gLog.info("Removing connection attempt to %s", userId.toString().c_str());
392 // SStartMessage *pStart = (*it);
393 m_lStart.erase(it);
394 break;
395 }
396 }
397 }
398 else if (strCmd == "RNG")
399 {
400 string strSessionID = packet->GetParameter();
401 string strServer = packet->GetParameter();
402 packet->SkipParameter(); // 'CKI'
403 string strCookie = packet->GetParameter();
404 Licq::UserId userId(myOwnerId, packet->GetParameter());
405
406 MSNSBConnectAnswer(strServer, strSessionID, strCookie, userId);
407 }
408 else if (strCmd == "MSG")
409 {
410 packet->SkipParameter(); // 'Hotmail'
411 packet->SkipParameter(); // 'Hotmail' again
412 packet->SkipParameter(); // size
413 packet->SkipRN(); // Skip \r\n
414 packet->ParseHeaders();
415
416 string strType = packet->GetValue("Content-Type");
417
418 if (strType.find("text/x-msmsgsprofile") != string::npos)
419 {
420 m_strMSPAuth = packet->GetValue("MSPAuth");
421 m_strSID = packet->GetValue("sid");
422 m_strKV = packet->GetValue("kv");
423 m_nSessionStart = time(0);
424
425 // We might have another packet attached
426 //packet->SkipRN();
427 }
428 else if (strType.find("text/x-msmsgsinitialemailnotification") != string::npos)
429 {
430 // Email alert when we sign in
431
432 // Get the next part..
433 packet->SkipRN();
434 packet->ParseHeaders();
435 }
436 else if (strType.find("text/x-msmsgsemailnotification") != string::npos)
437 {
438 // Email we get while signed in
439
440 // Get the next part..
441 packet->SkipRN();
442 packet->ParseHeaders();
443
444 string strFrom = packet->GetValue("From");
445 string strFromAddr = packet->GetValue("From-Addr");
446 string strSubject = packet->GetValue("Subject");
447
448 const string toHash = m_strMSPAuth + "9" + myPassword;
449 const string hexDigest = Licq::Md5::hashToHexString(toHash);
450
451 gLog.info("New email from %s (%s)", strFrom.c_str(), strFromAddr.c_str());
452 Licq::EventEmailAlert* pEmailAlert = new Licq::EventEmailAlert(
453 strFrom, myOwnerId.accountId(), strFromAddr, strSubject, time(0),
454 m_strMSPAuth, m_strSID, m_strKV, packet->GetValue("id"),
455 packet->GetValue("Post-URL"), packet->GetValue("Message-URL"),
456 hexDigest, m_nSessionStart);
457
458 Licq::OwnerWriteGuard o(myOwnerId);
459 if (Licq::gDaemon.addUserEvent(*o, pEmailAlert))
460 {
461 pEmailAlert->AddToHistory(*o, true);
462 gOnEventManager.performOnEvent(OnEventData::OnEventSysMsg, *o);
463 }
464 }
465 }
466 else if (strCmd == "QNG")
467 {
468 m_bWaitingPingReply = false;
469 }
470 else if (strCmd == "913")
471 {
472 unsigned long nSeq = packet->GetParameterUnsignedLong();
473
474 // Search pStart for this sequence, mark it as an error, send the
475 // signals to the daemon and remove these item from the list.
476 SStartMessage *pStart = 0;
477 StartList::iterator it;
478 for (it = m_lStart.begin(); it != m_lStart.end(); it++)
479 {
480 if ((*it)->m_nSeq == nSeq)
481 {
482 gLog.error("Cannot send messages while invisible");
483 pStart = *it;
484 pStart->m_pEvent->m_eResult = Licq::Event::ResultFailed;
485 Licq::gPluginManager.pushPluginEvent(pStart->m_pEvent);
486 m_lStart.erase(it);
487 break;
488 }
489 }
490 }
491 else if (strCmd == "GTC")
492 {
493 }
494 else if (strCmd == "BLP")
495 {
496 }
497 else if (strCmd == "PRP")
498 {
499 }
500 else if (strCmd == "QRY")
501 {
502 m_bCanPing = true;
503 }
504 else if (strCmd == "NOT")
505 {
506 // For the moment, skip the notification... consider it spam from MSN
507 unsigned long nSize = packet->GetParameterUnsignedLong(); // size
508 packet->SkipRN(); // Skip \r\n
509 packet->Skip(nSize);
510 }
511 else
512 {
513 gLog.warning("Unhandled command (%s)", strCmd.c_str());
514 }
515
516 if (pReply)
517 SendPacket(pReply);
518 }
519 }
520
SendPacket(CMSNPacket * p)521 void CMSN::SendPacket(CMSNPacket *p)
522 {
523 assert(myServerSocket != NULL);
524 if (!myServerSocket->send(*p->getBuffer()))
525 MSNLogoff(true);
526
527 delete p;
528 }
529
Logon(const Licq::UserId & ownerId,unsigned status,string host,int port)530 void CMSN::Logon(const Licq::UserId& ownerId, unsigned status, string host, int port)
531 {
532 if (status == User::OfflineStatus)
533 return;
534
535 myOwnerId = ownerId;
536
537 {
538 Licq::OwnerReadGuard o(myOwnerId);
539 if (!o.isLocked())
540 {
541 gLog.error("No owner set");
542 return;
543 }
544 myPassword = o->password();
545 if (host.empty())
546 host = o->serverHost();
547 if (port == 0)
548 port = o->serverPort();
549 }
550
551 if (host.empty())
552 host = defaultServerHost();
553 if (port <= 0)
554 port = defaultServerPort();
555
556 myServerSocket = new Licq::TCPSocket(myOwnerId);
557 gLog.info("Server found at %s:%d", host.c_str(), port);
558
559 if (!myServerSocket->connectTo(host, port))
560 {
561 gLog.info("Connect failed to %s", host.c_str());
562 delete myServerSocket;
563 myServerSocket = NULL;
564 return;
565 }
566
567 myMainLoop.addSocket(myServerSocket, this);
568
569 CMSNPacket *pHello = new CPS_MSNVersion();
570 SendPacket(pHello);
571 myStatus = status;
572 }
573
MSNChangeStatus(unsigned status)574 void CMSN::MSNChangeStatus(unsigned status)
575 {
576 string msnStatus;
577 if (status & User::InvisibleStatus)
578 {
579 msnStatus = "HDN";
580 status = User::OnlineStatus | User::InvisibleStatus;
581 }
582 else if (status & User::FreeForChatStatus || status == User::OnlineStatus)
583 {
584 msnStatus = "NLN";
585 status = User::OnlineStatus;
586 }
587 else if (status & (User::OccupiedStatus | User::DoNotDisturbStatus))
588 {
589 msnStatus = "BSY";
590 status = User::OnlineStatus | User::OccupiedStatus;
591 }
592 else
593 {
594 msnStatus = "AWY";
595 status = User::OnlineStatus | User::AwayStatus;
596 }
597
598 CMSNPacket* pSend = new CPS_MSNChangeStatus(msnStatus);
599 SendPacket(pSend);
600 myStatus = status;
601 }
602
MSNLogoff(bool bDisconnected)603 void CMSN::MSNLogoff(bool bDisconnected)
604 {
605 if (myServerSocket == NULL)
606 return;
607
608 if (!bDisconnected)
609 {
610 CMSNPacket *pSend = new CPS_MSNLogoff();
611 SendPacket(pSend);
612 }
613
614 myStatus = User::OfflineStatus;
615
616 // Don't try to send any more pings
617 m_bCanPing = false;
618
619 // Close the server socket
620 closeSocket(myServerSocket, false);
621 myServerSocket = NULL;
622
623 // Close user sockets and update the daemon
624 {
625 Licq::UserListGuard userList(myOwnerId);
626 BOOST_FOREACH(Licq::User* user, **userList)
627 {
628 UserWriteGuard u(dynamic_cast<User*>(user));
629 if (u->normalSocketDesc() != NULL)
630 {
631 closeSocket(u->normalSocketDesc(), false);
632 u->clearAllSocketDesc();
633 }
634 if (u->isOnline())
635 u->statusChanged(User::OfflineStatus);
636 }
637 }
638
639 Licq::OwnerWriteGuard o(myOwnerId);
640 if (o.isLocked())
641 o->statusChanged(Licq::User::OfflineStatus);
642 }
643
MSNAddUser(const UserId & userId)644 void CMSN::MSNAddUser(const UserId& userId)
645 {
646 {
647 Licq::UserWriteGuard u(userId);
648 if (u.isLocked())
649 {
650 u->SetEnableSave(false);
651 u->setUserEncoding("UTF-8");
652 u->SetEnableSave(true);
653 u->save(Licq::User::SaveLicqInfo);
654 }
655 }
656
657 CMSNPacket* pSend = new CPS_MSNAddUser(userId.accountId(), CONTACT_LIST);
658 SendPacket(pSend);
659 }
660
MSNRemoveUser(const UserId & userId)661 void CMSN::MSNRemoveUser(const UserId& userId)
662 {
663 CMSNPacket* pSend = new CPS_MSNRemoveUser(userId.accountId(), CONTACT_LIST);
664 SendPacket(pSend);
665 Licq::gUserManager.removeLocalUser(userId);
666 }
667
MSNRenameUser(const UserId & userId)668 void CMSN::MSNRenameUser(const UserId& userId)
669 {
670 string strNick;
671 {
672 Licq::UserReadGuard u(userId);
673 if (!u.isLocked())
674 return;
675 strNick = u->getAlias();
676 }
677
678 CMSNPacket* pSend = new CPS_MSNRenameUser(userId.accountId(), Encode(strNick));
679 SendPacket(pSend);
680 }
681
MSNGrantAuth(const UserId & userId)682 void CMSN::MSNGrantAuth(const UserId& userId)
683 {
684 CMSNPacket* pSend = new CPS_MSNAddUser(userId.accountId(), ALLOW_LIST);
685 SendPacket(pSend);
686 }
687
MSNUpdateUser(const string & alias)688 void CMSN::MSNUpdateUser(const string& alias)
689 {
690 CMSNPacket* pSend = new CPS_MSNRenameUser(myOwnerId.accountId(), Encode(alias));
691 SendPacket(pSend);
692 }
693
MSNBlockUser(const UserId & userId)694 void CMSN::MSNBlockUser(const UserId& userId)
695 {
696 {
697 Licq::UserWriteGuard u(userId);
698 if (!u.isLocked())
699 return;
700 u->SetInvisibleList(true);
701 }
702
703 CMSNPacket* pRem = new CPS_MSNRemoveUser(userId.accountId(), ALLOW_LIST);
704 gLog.info("Removing user %s from the allow list", userId.toString().c_str());
705 SendPacket(pRem);
706 CMSNPacket* pAdd = new CPS_MSNAddUser(userId.accountId(), BLOCK_LIST);
707 gLog.info("Adding user %s to the block list", userId.toString().c_str());
708 SendPacket(pAdd);
709 }
710
MSNUnblockUser(const UserId & userId)711 void CMSN::MSNUnblockUser(const UserId& userId)
712 {
713 {
714 Licq::UserWriteGuard u(userId);
715 if (!u.isLocked())
716 return;
717 u->SetInvisibleList(false);
718 }
719
720 CMSNPacket* pRem = new CPS_MSNRemoveUser(userId.accountId(), BLOCK_LIST);
721 gLog.info("Removing user %s from the block list", userId.toString().c_str());
722 SendPacket(pRem);
723 CMSNPacket* pAdd = new CPS_MSNAddUser(userId.accountId(), ALLOW_LIST);
724 gLog.info("Adding user %s to the allow list", userId.toString().c_str());
725 SendPacket(pAdd);
726 }
727
MSNGetDisplayPicture(const Licq::UserId & userId,const string & strMSNObject)728 void CMSN::MSNGetDisplayPicture(const Licq::UserId& userId, const string &strMSNObject)
729 {
730 // If we are invisible, this will result in an error, so don't allow it
731 if (myStatus & User::InvisibleStatus)
732 return;
733
734 CMSNPacket* pGetMSNDP = new CPS_MSNInvitation(userId.accountId(), myOwnerId.accountId(), strMSNObject);
735 CMSNP2PPacket *p = (CMSNP2PPacket *)(pGetMSNDP);
736 CMSNDataEvent *pDataResponse = new CMSNDataEvent(MSN_DP_EVENT,
737 p->SessionId(), p->BaseId(), userId, myOwnerId, p->CallGUID(), this);
738 WaitDataEvent(pDataResponse);
739 gLog.info("Requesting %s's display picture", userId.toString().c_str());
740 MSNSendInvitation(userId, pGetMSNDP);
741 }
742
sendServerPing()743 void CMSN::sendServerPing()
744 {
745 if (m_bWaitingPingReply)
746 {
747 gLog.info("Ping timeout, reconnecting...");
748 m_bWaitingPingReply = false;
749 unsigned status = myStatus;
750 MSNLogoff();
751 Logon(myOwnerId, status);
752 }
753 else if (m_bCanPing)
754 {
755 CMSNPacket* pSend = new CPS_MSNPing();
756 SendPacket(pSend);
757
758 m_bWaitingPingReply = true;
759 }
760 }
761