/* * notificationserver.cpp * libmsn * * Created by Mark Rowe on Mon Mar 22 2004. * Refactored by Tiago Salem Herrmann on 08/2007. * Copyright (c) 2004 Mark Rowe. All rights reserved. * Copyright (c) 2007 Tiago Salem Herrmann. All rights reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "notificationserver.h" #include "errorcodes.h" #include "externals.h" #include "md5.h" #include "util.h" #include "soap.h" #include #include #include #ifndef WIN32 #include #include #include #include #include #else #include #endif #include #include #include #include "xmlParser.h" namespace MSN { std::map &)> NotificationServerConnection::commandHandlers; std::map &, std::string, std::string)> NotificationServerConnection::messageHandlers; NotificationServerConnection::NotificationServerConnection(Passport username_, std::string password_, Callbacks & cb_) : Connection(), auth(username_, password_), myPassport(username_), m_clientId(0), externalCallbacks(cb_), _connectionState(NS_DISCONNECTED), generatingLockkey(false), removingOIM(false), bplSetting('B') { msnobj.setCreator(username_); registerHandlers(); } NotificationServerConnection::~NotificationServerConnection() { if (this->connectionState() != NS_DISCONNECTED) this->disconnect(); } Connection *NotificationServerConnection::connectionWithSocket(void *sock) { if (this->sock == sock) return this; std::vector & list = _switchboardConnections; std::vector::iterator i = list.begin(); for (; i != list.end(); i++) { Connection *c = (*i)->connectionWithSocket(sock); if (c) return c; } std::vector & list2 = _SoapConnections; std::vector::iterator d = list2.begin(); for (; d != list2.end(); d++) { if((*d)->sock == sock ) return (*d); } return NULL; } SwitchboardServerConnection *NotificationServerConnection::switchboardWithOnlyUser(Passport username) { if (this->connectionState() >= NS_CONNECTED) { std::vector & list = _switchboardConnections; std::vector::iterator i = list.begin(); for (; i != list.end(); i++) { if ((*i)->users.size() == 1 && *((*i)->users.begin()) == username) return *i; } } return NULL; } const std::vector & NotificationServerConnection::switchboardConnections() { this->assertConnectionStateIsAtLeast(NS_CONNECTED); return _switchboardConnections; } void NotificationServerConnection::addSwitchboardConnection(SwitchboardServerConnection *c) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); _switchboardConnections.push_back(c); } void NotificationServerConnection::addSoapConnection(Soap *s) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); _SoapConnections.push_back(s); } void NotificationServerConnection::removeSwitchboardConnection(SwitchboardServerConnection *c) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); std::vector::iterator it; for(it = _switchboardConnections.begin(); it != _switchboardConnections.end(); it++) { if((*it) == c) { _switchboardConnections.erase(it); return; } } } void NotificationServerConnection::removeSoapConnection(Soap *s) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); std::vector::iterator it; for(it = _SoapConnections.begin(); it != _SoapConnections.end(); it++) { if((*it) == s) { _SoapConnections.erase(it); return; } } } void NotificationServerConnection::addCallback(NotificationServerCallback callback, int trid, void *data) { this->assertConnectionStateIsAtLeast(NS_CONNECTING); this->callbacks[trid] = std::make_pair(callback, data); } void NotificationServerConnection::removeCallback(int trid) { this->assertConnectionStateIsAtLeast(NS_CONNECTING); this->callbacks.erase(trid); } void NotificationServerConnection::registerHandlers() { if (commandHandlers.size() == 0) { commandHandlers["OUT"] = &NotificationServerConnection::handle_OUT; commandHandlers["RML"] = &NotificationServerConnection::handle_RML; commandHandlers["BLP"] = &NotificationServerConnection::handle_BLP; commandHandlers["CHG"] = &NotificationServerConnection::handle_CHG; commandHandlers["CHL"] = &NotificationServerConnection::handle_CHL; commandHandlers["ILN"] = &NotificationServerConnection::handle_ILN; commandHandlers["NLN"] = &NotificationServerConnection::handle_NLN; commandHandlers["FLN"] = &NotificationServerConnection::handle_FLN; commandHandlers["MSG"] = &NotificationServerConnection::handle_MSG; commandHandlers["PRP"] = &NotificationServerConnection::handle_PRP; commandHandlers["UBX"] = &NotificationServerConnection::handle_UBX; commandHandlers["GCF"] = &NotificationServerConnection::handle_GCF; commandHandlers["ADL"] = &NotificationServerConnection::handle_ADL; commandHandlers["UBN"] = &NotificationServerConnection::handle_UBN; commandHandlers["FQY"] = &NotificationServerConnection::handle_FQY; } if (messageHandlers.size() == 0) { messageHandlers["text/x-msmsgsinitialemailnotification"] = &NotificationServerConnection::message_initial_email_notification; messageHandlers["text/x-msmsgsinitialmdatanotification"] = &NotificationServerConnection::message_initialmdatanotification; messageHandlers["text/x-msmsgsemailnotification"] = &NotificationServerConnection::message_email_notification; messageHandlers["text/x-msmsgsprofile"] = &NotificationServerConnection::message_msmsgsprofile; messageHandlers["text/x-msmsgsoimnotification"] = &NotificationServerConnection::message_oimnotification; } } void NotificationServerConnection::dispatchCommand(std::vector & args) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); std::map &)>::iterator i = commandHandlers.find(args[0]); if (i != commandHandlers.end()) (this->*commandHandlers[args[0]])(args); } void NotificationServerConnection::disconnectNS() { std::ostringstream buf_; buf_ << "OUT\r\n"; if (this->write(buf_) != buf_.str().size()) return; disconnect(); } void NotificationServerConnection::handle_OUT(std::vector & args) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); if (args.size() > 1) { if (args[1] == "OTH") { this->myNotificationServer()->externalCallbacks.showError(this, "You have logged onto MSN twice at once. Your MSN session will now terminate."); } else if (args[1] == "SSD") { this->myNotificationServer()->externalCallbacks.showError(this, "This MSN server is going down for maintenance. Your MSN session will now terminate."); } else { this->myNotificationServer()->externalCallbacks.showError(this, (std::string("The MSN server has terminated the connection with an unknown reason code. Please report this code: ") + args[1]).c_str()); } } this->disconnect(); } void NotificationServerConnection::handle_RML(std::vector & args) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); int msglen; std::string msg; if(args[2] != "OK" && args[2] != "OK") return; // TODO - raise an error msglen = decimalFromString(args[2]); msg = this->readBuffer.substr(0, msglen); this->readBuffer = this->readBuffer.substr(msglen); XMLNode rml_data = XMLNode::parseString( msg.c_str() ); int nDomains = rml_data.nChildNode("d"); for(int i=0; imyNotificationServer()->externalCallbacks.removedListEntry(this, list_number, passport); } } } void NotificationServerConnection::handle_BLP(std::vector & args) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); this->myNotificationServer()->externalCallbacks.gotBLP(this, args[3][0]); } void NotificationServerConnection::handle_CHG(std::vector & args) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); this->myNotificationServer()->externalCallbacks.changedStatus(this, buddyStatusFromString(args[2])); } void NotificationServerConnection::handle_CHL(std::vector & args) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); std::ostringstream buf_; buf_ << "QRY " << this->trID++ << " " << szClientID << " 32\r\n"; if (write(buf_) != buf_.str().size()) return; char b[33]; memset(&b,0,33); DoMSNP11Challenge(args[2].c_str(),b); // send the md5 std::string a(b); write(a, false); } void NotificationServerConnection::handle_ILN(std::vector & args) { this->assertConnectionStateIs(NS_CONNECTED); if(args.size() > 7) this->myNotificationServer()->externalCallbacks.buddyChangedStatus(this, args[3], decodeURL(args[5]), buddyStatusFromString(args[2]), decimalFromString(args[6]), decodeURL(args[7])); else this->myNotificationServer()->externalCallbacks.buddyChangedStatus(this, args[3], decodeURL(args[5]), buddyStatusFromString(args[2]), decimalFromString(args[6]), ""); } void NotificationServerConnection::handle_NLN(std::vector & args) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); if(args.size() > 6) this->myNotificationServer()->externalCallbacks.buddyChangedStatus(this, args[2], decodeURL(args[4]), buddyStatusFromString(args[1]), decimalFromString(args[5]), decodeURL(args[6])); else this->myNotificationServer()->externalCallbacks.buddyChangedStatus(this, args[2], decodeURL(args[4]), buddyStatusFromString(args[1]), decimalFromString(args[5]), ""); } void NotificationServerConnection::handle_FLN(std::vector & args) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); this->myNotificationServer()->externalCallbacks.buddyOffline(this, args[1]); } void NotificationServerConnection::handle_UBN(std::vector & args) { // TODO - UBN is a way to exchange data through notification server this->assertConnectionStateIsAtLeast(NS_CONNECTED); int msglen; std::string msg; msglen = decimalFromString(args[3]); msg = this->readBuffer.substr(0, msglen); this->readBuffer = this->readBuffer.substr(msglen); } void NotificationServerConnection::handle_FQY(std::vector & args) { // TODO - I dont know what it means yet this->assertConnectionStateIsAtLeast(NS_CONNECTED); int msglen; std::string msg; msglen = decimalFromString(args[2]); msg = this->readBuffer.substr(0, msglen); this->readBuffer = this->readBuffer.substr(msglen); } void NotificationServerConnection::callback_URL(std::vector & args, int trid, void *data) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); char b[33]; MSN::hotmailInfo info; info.rru = args[2]; info.url = args[3]; info.id = args[4]; info.sl = toStr(time(NULL) - decimalFromString(login_time)); info.MSPAuth = MSPAuth; info.sid = sid; info.kv = kv; // calculate creds std::string creds_tmp = MSPAuth + info.sl + this->auth.password; memset(&b,0,33); md5_state_t state; md5_byte_t digest[16]; int di; md5_init(&state); md5_append(&state, (const md5_byte_t *)creds_tmp.c_str(), creds_tmp.size()); md5_finish(&state, digest); // convert to string for (di = 0; di < 16; ++di) sprintf(&b[2*di], "%02x", digest[di]); std::string creds(b); info.creds = creds; this->myNotificationServer()->externalCallbacks.gotInboxUrl(this, info); } void NotificationServerConnection::handle_MSG(std::vector & args) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); int msglen; std::string msg; std::string mime; std::string body; size_t tmp; msglen = decimalFromString(args[3]); msg = this->readBuffer.substr(0, msglen); this->readBuffer = this->readBuffer.substr(msglen); body = msg.substr(msg.find("\r\n\r\n") + 4); mime = msg.substr(0, msg.size() - body.size()); std::string contentType; Message::Headers headers = Message::Headers(mime); contentType = headers["Content-Type"]; if ((tmp = contentType.find("; charset")) != std::string::npos) contentType = contentType.substr(0, tmp); std::map &, std::string, std::string)>::iterator i = messageHandlers.find(contentType); if (i != messageHandlers.end()) (this->*(messageHandlers[contentType]))(args, mime, body); } void NotificationServerConnection::message_initial_email_notification(std::vector & args, std::string mime, std::string body) { std::string unreadInbox; std::string unreadFolder; int unreadInboxCount = 0, unreadFolderCount = 0; // Initial email notifications body is a set of MIME headers Message::Headers headers = Message::Headers(body); unreadInbox = headers["Inbox-Unread"]; unreadFolder = headers["Folders-Unread"]; if (! unreadInbox.empty()) unreadInboxCount = decimalFromString(unreadInbox); if (! unreadFolder.empty()) unreadFolderCount = decimalFromString(unreadFolder); // this->myNotificationServer()->externalCallbacks.gotInitialEmailNotification(this, unreadInboxCount, unreadFolderCount); } void NotificationServerConnection::message_email_notification(std::vector & args, std::string mime, std::string body) { // New email notifications body is a set of MIME headers Message::Headers headers = Message::Headers(body); std::string from = headers["From-Addr"]; std::string subject = headers["Subject"]; this->myNotificationServer()->externalCallbacks.gotNewEmailNotification(this, from, subject); } void NotificationServerConnection::message_msmsgsprofile(std::vector & args, std::string mime, std::string body) { direct_connection=false; Message::Headers headers = Message::Headers(mime); server_reported_ip = headers["ClientIP"]; server_reported_port = headers["ClientPort"]; login_time = headers["LoginTime"]; MSPAuth = headers["MSPAuth"]; sid = headers["sid"]; kv = headers["kv"]; if (login_time.empty()) //IN MSNP9 there is no logintime it seems, so set it manualy { time_t actualTime; std::stringstream os; time(&actualTime); os << actualTime; login_time = os.str(); } this->myNotificationServer()->externalCallbacks.gotNewConnection(this); // TODO - test portability to windows and mac, probably solved by ifdefs, // or with an external callback to user application // search on local machine the ip reported by the server /* int s = socket (PF_INET, SOCK_STREAM, 0); for (int i=1;;i++) { struct ifreq ifr; struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr; char *ip; ifr.ifr_ifindex = i; if (ioctl (s, SIOCGIFNAME, &ifr) < 0) break; if (ioctl (s, SIOCGIFADDR, &ifr) < 0) continue; ip = inet_ntoa (sin->sin_addr); std::string ip2(ip); if(ip2==server_reported_ip) direct_connection=true; } close (s); */ } void NotificationServerConnection::message_initialmdatanotification(std::vector & args, std::string mime, std::string body) { Message::Headers headers = Message::Headers(body); std::string maildata = headers["Mail-Data"]; XMLNode domTree = XMLNode::parseString( maildata.c_str() ); //Mail-Data: 2110409600204800 //Mail-Data: 3220409600204800 //Mail-Data: 3120409600204800 //empty inbox //Mail-Data: 0050409600204800 int emails = domTree.nChildNode("E"); if (emails) { XMLNode curr_element = domTree.getChildNode("E",0); int inbox_msgs = decimalFromString(curr_element.getChildNode("I").getText()); int inbox_unread = decimalFromString(curr_element.getChildNode("IU").getText()); int other_folders = decimalFromString(curr_element.getChildNode("O").getText()); int other_folders_unread = decimalFromString(curr_element.getChildNode("OU").getText()); this->myNotificationServer()->externalCallbacks. gotInitialEmailNotification(this, inbox_msgs, inbox_unread, other_folders, other_folders_unread); } // try to get OIM information message_oimnotification(args, mime, body); } void NotificationServerConnection::message_oimnotification(std::vector & args, std::string mime, std::string body) { Message::Headers headers = Message::Headers(body); std::string maildata = headers["Mail-Data"]; if(maildata == "too-large") { // more than 25 OIM's // request OIM list through soap Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->getMailData(); return; } // process maildata gotMailData(maildata); } void NotificationServerConnection::gotSoapMailData(Soap & soapConnection, std::string maildata) { gotMailData(maildata); } void NotificationServerConnection::gotMailData(std::string maildata) { std::vector messages; XMLNode domTree = XMLNode::parseString( maildata.c_str() ); int oims = domTree.nChildNode("M"); if (oims) { for(int i=0;i friendlyName; // if we do not have '?', it is just the email if(temp_oim.fromFN.find("?") != std::string::npos) { friendlyName=splitString(temp_oim.fromFN,"?"); // TODO - handle the encoding (friendlyName[1]) if(friendlyName[2]=="B") { temp_oim.fromFN=b64_decode(friendlyName[3].c_str()); } if(friendlyName[2]=="Q") { // Quoted-Printable, is similar to URL encoding, // but uses "=" instead of "%". std::string change = friendlyName[3]; // changes the = by % for(unsigned int a=0;amyNotificationServer()->externalCallbacks.gotOIMList(this, messages); } domTree.deleteNodeContent('Y'); } void NotificationServerConnection::handle_RNG(std::vector & args) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); SwitchboardServerConnection::AuthData auth = SwitchboardServerConnection::AuthData(this->auth.username, args[1], args[4]); SwitchboardServerConnection *newSBconn = new SwitchboardServerConnection(auth, *this); this->addSwitchboardConnection(newSBconn); std::pair server_address = splitServerAddress(args[2]); newSBconn->connect(server_address.first, server_address.second); } void NotificationServerConnection::handle_PRP(std::vector & args) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); if(this->_connectionState == NS_SYNCHRONISING) { this->myNotificationServer()->externalCallbacks.gotFriendlyName(this, decodeURL(args[3])); this->myDisplayName = decodeURL(args[3]); this->myNotificationServer()->externalCallbacks.connectionReady(this); // the initial process ends here this->setConnectionState(NS_CONNECTED); return; } if ( args[2] == "MFN") //when you set manually your FriendlyName { this->myNotificationServer()->externalCallbacks.gotFriendlyName(this, decodeURL(args[3])); this->myDisplayName = decodeURL(args[3]); }// TODO - Implement other PRP commands: MBE WWE } void NotificationServerConnection::handle_GCF(std::vector & args) { int msglen; std::string msg; this->assertConnectionStateIsAtLeast(NS_CONNECTED); // we do not use it so far. throw it away msglen = decimalFromString(args[2]); msg = this->readBuffer.substr(0, msglen); this->readBuffer = this->readBuffer.substr(msglen); } void NotificationServerConnection::handle_ADL(std::vector & args) { int msglen; std::string msg; this->assertConnectionStateIsAtLeast(NS_CONNECTED); if(args[2] =="OK" && (this->_connectionState == NS_SYNCHRONISING)) { if(adl_packets.empty()) { // no more adl packets to send! // now you need the change the nickname and set the status // to complete the initial connection process // it is not possible to use setFriendlyName // because we cannot send soap requests at this time std::ostringstream buf_; if(this->myDisplayName.empty()) this->myDisplayName = myPassport; if(server_email_verified != "0") { // our email is verified buf_ << "PRP " << this->trID++ << " MFN " << encodeURL(this->myDisplayName) << "\r\n"; write(buf_); } else { // not verified, so we cant change our displayName this->myNotificationServer()->externalCallbacks.connectionReady(this); // the initial process ends here this->setConnectionState(NS_CONNECTED); } return; } else { // send each adl packet at a time std::string adl_payload = adl_packets.front(); adl_packets.pop_front(); std::ostringstream buf_; buf_ << "ADL " << this->trID++ << " " << adl_payload.length() << "\r\n"; buf_ << adl_payload; if (write(buf_) != buf_.str().size()) return; } } // I reach here when ADL has payload msglen = decimalFromString(args[2]); msg = this->readBuffer.substr(0, msglen); this->readBuffer = this->readBuffer.substr(msglen); // ADL 0 70 // // XMLNode adl_data = XMLNode::parseString( msg.c_str() ); int nDomains = adl_data.nChildNode("d"); for(int i=0; imyNotificationServer()->externalCallbacks.addedListEntry(this, list_number, passport, fname); } } } void NotificationServerConnection::handle_UBX(std::vector & args) { int msglen; personalInfo pInfo; std::string msg,media,psm; MSN::Passport fromPassport = args[1]; this->assertConnectionStateIsAtLeast(NS_CONNECTED); msglen = decimalFromString(args[3]); msg = this->readBuffer.substr(0, msglen); this->readBuffer = this->readBuffer.substr(msglen); // some buggy clients send no data in UBX command if( msg.length() < 10 ) return; XMLNode ubx_data = XMLNode::parseString( msg.c_str() ); const char *a = ubx_data.getChildNode("PSM").getText(); if(a) { psm = a; pInfo.PSM = psm; } const char *m = ubx_data.getChildNode("CurrentMedia").getText(); if(m) { media = m; // the splitString will drop the first NULL position. // we need it to keep the order of the following fields. std::vector media1 = splitString(media, "\\0"); if(media1.size()>=4) // at least 4 fields. Type, Enabled, format, data { // if we have some field, so ... int i=0; if (media.find("\\0")==0) { // if starts with \0 there is no // App field. It is optional. pInfo.mediaApp = ""; } else { pInfo.mediaApp = media1[i++]; } pInfo.mediaType = media1[i++]; pInfo.mediaIsEnabled = decimalFromString(media1[i++]); if(pInfo.mediaIsEnabled) { pInfo.mediaFormat = media1[i++]; for(unsigned int b=i; b < media1.size(); b++) { pInfo.mediaLines.push_back(media1[i++]); } } } } this->myNotificationServer()->externalCallbacks.buddyChangedPersonalInfo(this, fromPassport, pInfo); } void NotificationServerConnection::setState(BuddyStatus state, uint clientID) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); std::ostringstream buf_; std::string xml; if(msnobj.getMSNObjectXMLByType(3,xml)) buf_ << "CHG " << this->trID++ << " " << buddyStatusToString(state) << " "<< unsignedToStr(clientID) << " " << encodeURL(xml) << "\r\n"; else buf_ << "CHG " << this->trID++ << " " << buddyStatusToString(state) << " " << unsignedToStr(clientID) << "\r\n"; write(buf_); } void NotificationServerConnection::setBLP(char setting) { if (setting != 'A' || setting != 'B') return; if(this->_connectionState == NS_CONNECTED) { std::ostringstream buf_; this->bplSetting = setting; buf_ << "BLP " << this->trID++ << " " << setting << "L\r\n"; write(buf_); } else { this->bplSetting = setting; } } void NotificationServerConnection::setFriendlyName(std::string friendlyName, bool updateServer) throw (std::runtime_error) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); if(friendlyName.empty()) return; if (friendlyName.size() > 387) throw std::runtime_error("Friendly name too long!"); if(updateServer) { // update nickname on server Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->changeDisplayName(friendlyName); } else { this->myDisplayName = friendlyName; std::ostringstream buf_; buf_ << "PRP " << this->trID++ << " MFN " << encodeURL(friendlyName) << "\r\n"; write(buf_); } } void NotificationServerConnection::setPersonalStatus(personalInfo pInfo) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); std::string tempMedia; XMLNode data = XMLNode::createXMLTopNode("Data"); XMLNode PSM = XMLNode::createXMLTopNode("PSM"); XMLNode CurrentMedia = XMLNode::createXMLTopNode("CurrentMedia"); XMLNode MachineGuid = XMLNode::createXMLTopNode("MachineGuid"); PSM.addText( pInfo.PSM.c_str() ); if(pInfo.mediaIsEnabled) { tempMedia = pInfo.mediaApp +"\\0"+ pInfo.mediaType+"\\0"+ toStr(pInfo.mediaIsEnabled)+"\\0"+ pInfo.mediaFormat +"\\0"; std::vector::iterator i = pInfo.mediaLines.begin(); for(;i!=pInfo.mediaLines.end();i++) { tempMedia+=(*i); tempMedia+="\\0"; } } CurrentMedia.addText( tempMedia.c_str() ); data.addChild(PSM); data.addChild(CurrentMedia); char *payload1=data.createXMLString(false); std::string payload(payload1); free(payload1); std::ostringstream buf_; buf_ << "UUX " << this->trID++ << " " << payload.length() << "\r\n"; buf_ << payload; write(buf_); } void NotificationServerConnection::blockContact(Passport buddyName) { Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->removeContactFromList(buddyName,LST_AL); soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->addContactToList(buddyName,LST_BL); } void NotificationServerConnection::unblockContact(Passport buddyName) { Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->removeContactFromList(buddyName,LST_BL); soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->addContactToList(buddyName,LST_AL); } void NotificationServerConnection::addToAddressBook(Passport buddyName, std::string displayName) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->addContactToAddressBook(buddyName, displayName); } void NotificationServerConnection::enableContactOnAddressBook(std::string contactId, std::string passport) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->enableContactOnAddressBook(contactId, passport, this->myDisplayName); } void NotificationServerConnection::disableContactOnAddressBook(std::string contactId, std::string passport) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->disableContactFromAddressBook(contactId,passport); } void NotificationServerConnection::delFromAddressBook(std::string contactId, std::string passport) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); std::vector passport2 = splitString(passport, "@"); std::string user = passport2[0]; std::string domain = passport2[1]; Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->delContactFromAddressBook(contactId,passport); } void NotificationServerConnection::addToList(MSN::ContactList list, Passport buddyName) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->addContactToList(buddyName,list); } void NotificationServerConnection::removeFromList(MSN::ContactList list, Passport buddyName) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->removeContactFromList(buddyName,list); } void NotificationServerConnection::addToGroup(std::string groupId, std::string contactId) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->addContactToGroup(groupId, contactId); } void NotificationServerConnection::removeFromGroup(std::string groupId, std::string contactId) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->delContactFromGroup(groupId, contactId); } void NotificationServerConnection::addGroup(std::string groupName) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->addGroup(groupName); } void NotificationServerConnection::removeGroup(std::string groupID) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->delGroup(groupID); } void NotificationServerConnection::renameGroup(std::string groupID, std::string newGroupName) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->renameGroup(groupID, newGroupName); } void NotificationServerConnection::synchronizeContactList(std::string lastChange) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); this->assertConnectionStateIsNot(NS_SYNCHRONISING); // we are synchronizing through soap requests now this->setConnectionState(NS_SYNCHRONISING); listInfo = new ListSyncInfo(lastChange); if(!listInfo) return; // TODO - raise an error if(!lastChange.length()) lastChange = "0"; listInfo->lastChange = lastChange; Soap *soapConnection; soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->getLists(listInfo); } void NotificationServerConnection::gotLists(Soap &soapConnection) { if(!listInfo) return; // TODO - raise an error Soap *soapConnection1; soapConnection1 = new Soap(*this, this->sitesToAuthList); // ask for Address book soapConnection1->getAddressBook(this->listInfo); } void NotificationServerConnection::gotAddressBook(Soap &soapConnection) { // TODO - sorry, I dont have choice. I need this here because the initial setFriendlyName // is called by handle_ADL(), which does not have access to info variable. this->myDisplayName = listInfo->myDisplayName; std::ostringstream buf_; // TODO - see what is the user choice: BL or AL // A value of 'AL' indicates that users that are neither on the client's Allow List or Buddy List will be allowed to see the client's online status and open a switchboard session with the client. A value of 'BL' indicates that these users will see the client as offline and will not be allowed to open a switchboard session. // http://msnpiki.msnfanatic.com/index.php/Command:BLP buf_ << "BLP " << this->trID << " " << this->bplSetting << "L\r\n"; if (write(buf_) != buf_.str().size()) return; this->addCallback(&NotificationServerConnection::callback_initialBPL, this->trID++, (void *)NULL); } void NotificationServerConnection::callback_initialBPL(std::vector & args, int trid, void *data) { this->assertConnectionStateIs(NS_SYNCHRONISING); this->removeCallback(trid); this->myNotificationServer()->externalCallbacks.gotBuddyListInfo(this, this->listInfo); delete this->listInfo; } void NotificationServerConnection::completeConnection(std::map & allContacts, void *info) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); // FIXME - handle the errors std::map > domains; std::string tempADL; // contains which number is. (i.e. 1 for FL, 2 for AL, 4 for BL) or the sum std::map tempList; std::map::iterator i; for (i = allContacts.begin(); i != allContacts.end(); i++) { std::vector parts = splitString((*i).first,"@"); if(tempList[(*i).first]==0) domains[parts[1]].push_back(parts[0]); // it does not allow LST_AL and LST_BL, as the server will refuse with a 241 error int privacyListMask = MSN::LST_AL | MSN::LST_BL; if ( ((*i).second & privacyListMask) == privacyListMask ) tempList[(*i).first] = (*i).second & ~MSN::LST_AL; else tempList[(*i).first] = (*i).second; } // deleting buddy information std::map::iterator d = listInfo->contactList.begin(); for(d; d != listInfo->contactList.end(); d++) { delete (*d).second; } // adding domains and users to xml: // The max payload of ADL command is about 7500 bytes. // so the code below should do that. // not using xmlParser due to the complex algorithm // TODO - What to do when there are no contacts? std::map >::iterator cur = domains.begin(); tempADL = ""; // for each domain for(; cur != domains.end(); cur++) { do { tempADL += ""; // for each user while(domains[(*cur).first].size()!=0) { std::string a((*cur).second[0]+"@"+(*cur).first); tempADL += ""; (*cur).second.erase((*cur).second.begin()); if (tempADL.length()>7400) break; } tempADL += ""; if (tempADL.length()>7400) { adl_packets.push_back("" + tempADL + "" ); tempADL = ""; } } while(domains[(*cur).first].size()!=0); } adl_packets.push_back("" + tempADL + "" ); // send the first one std::string adl_payload = adl_packets.front(); adl_packets.pop_front(); std::ostringstream buf_; buf_ << "ADL " << this->trID++ << " " << adl_payload.length() << "\r\n"; buf_ << adl_payload; if (write(buf_) != buf_.str().size()) return; } void NotificationServerConnection::sendPing() { this->assertConnectionStateIsAtLeast(NS_CONNECTED); std::string a("PNG\r\n"); write(a); } void NotificationServerConnection::requestSwitchboardConnection(const void *tag) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); SwitchboardServerConnection::AuthData *auth = new SwitchboardServerConnection::AuthData(this->auth.username, tag); std::ostringstream buf_; buf_ << "XFR " << this->trID << " SB\r\n"; if (write(buf_) != buf_.str().size()) return; this->addCallback(&NotificationServerConnection::callback_TransferToSwitchboard, this->trID++, (void *)auth); } template class _sameUserName { Buddy buddy; public: _sameUserName(const _Tp &__u) : buddy(__u) {}; bool operator()(const _Tp &__x) { return __x.userName == buddy.userName; } }; void NotificationServerConnection::socketConnectionCompleted() { this->assertConnectionStateIs(NS_CONNECTING); this->setConnectionState(NS_CONNECTED); Connection::socketConnectionCompleted(); // If an error occurs in Connection::socketConnectionCompleted, we // will be disconnected before we get here. if (this->connectionState() != NS_DISCONNECTED) { this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock); this->myNotificationServer()->externalCallbacks.registerSocket(this->sock, 1, 0, false); } } void NotificationServerConnection::connect(const std::string & hostname, unsigned int port) { this->assertConnectionStateIs(NS_DISCONNECTED); connectinfo *info = new connectinfo(this->auth.username, this->auth.password); this->info = info; if ((this->sock = this->myNotificationServer()->externalCallbacks.connectToServer(hostname, port, &this->connected)) == NULL) { this->myNotificationServer()->externalCallbacks.showError(this, "Could not connect to MSN server"); this->myNotificationServer()->externalCallbacks.closingConnection(this); return; } this->setConnectionState(NS_CONNECTING); this->myNotificationServer()->externalCallbacks.registerSocket(this->sock, 0, 1, false); if (this->connected) this->socketConnectionCompleted(); std::ostringstream buf_; buf_ << "VER " << this->trID << " MSNP15 CVR0\r\n"; if (this->write(buf_) != buf_.str().size()) return; this->addCallback(&NotificationServerConnection::callback_NegotiateCVR, this->trID++, (void *)info); } void NotificationServerConnection::connect(const std::string & hostname, unsigned int port, const Passport & username, const std::string & password) { this->auth.username = username; this->auth.password = password; this->connect(hostname, port); } void NotificationServerConnection::disconnect() { if (this->connectionState() == NS_DISCONNECTED) return; std::vector list = _switchboardConnections; std::vector::iterator i = list.begin(); for (; i != list.end(); ++i) { delete *i; } std::vector list2 = _SoapConnections; std::vector::iterator d = list2.begin(); for (; d != list2.end(); ++d) { delete *d; } this->callbacks.clear(); this->sitesToAuthList.erase(sitesToAuthList.begin(), sitesToAuthList.end()); SentQueuedOIMs.erase(SentQueuedOIMs.begin(), SentQueuedOIMs.end()); this->setConnectionState(NS_DISCONNECTED); this->myNotificationServer()->externalCallbacks.closingConnection(this); Connection::disconnect(); } void NotificationServerConnection::disconnectForTransfer() { this->assertConnectionStateIsNot(NS_DISCONNECTED); this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock); this->myNotificationServer()->externalCallbacks.closeSocket(this->sock); this->setConnectionState(NS_DISCONNECTED); } void NotificationServerConnection::handleIncomingData() { this->assertConnectionStateIsAtLeast(NS_CONNECTED); while (this->isWholeLineAvailable()) { std::vector args = this->getLine(); if(!args.size()) continue; if (args[0] == "MSG" || args[0] == "NOT" || args[0] == "IPG" || args[0] == "GCF" || args[0] == "UBX" || args[0] == "ADL" || args[0] == "RML") { int dataLength; if (args[0] == "MSG" || args[0] == "UBX") dataLength = decimalFromString(args[3]); else if(args[0] == "GCF" || args[0] == "ADL" || args[0] == "RML") dataLength = decimalFromString(args[2]); else dataLength = decimalFromString(args[1]); if (this->readBuffer.find("\r\n") + 2 + dataLength > this->readBuffer.size()) return; } this->readBuffer = this->readBuffer.substr(this->readBuffer.find("\r\n") + 2); int trid = 0; if (args.size() >= 6 && args[0] == "XFR" && args[2] == "NS") { // XFR TrID NS NotificationServerIP:Port 0 ThisServerIP:Port // 0 1 2 3 4 5 this->callbacks.clear(); // delete the callback data this->disconnectForTransfer(); std::pair server_address = splitServerAddress(args[3]); this->connect(server_address.first, server_address.second); return; } if (args.size() >= 7 && args[0] == "RNG") { // RNG SessionID SwitchboardServerIP:Port CKI AuthString InvitingUser InvitingDisplayName // 0 1 2 3 4 5 6 this->handle_RNG(args); return; } if (args.size() >= 2 && args[0] == "QNG") { // QNG seconds // 0 1 // ping response, ignore return; } if ((args.size() >= 3 && args[0] == "LST" ) || (args.size() >= 2 && (args[0] == "GTC" )) || (args.size() >= 3 && (args[0] == "BPR" || args[0] == "LSG" )) ) { // LST N=UserName F=FriendlyName C=GUID param groupID // 0 1 2 3 4 5 // // or // (GTC|BLP) [TrID] [ListVersion] Setting // 0 1 2 4 if (this->synctrid) { trid = this->synctrid; } else { trid = decimalFromString(args[1]); } } else if (args.size() > 1) { try { trid = decimalFromString(args[1]); } catch (...) { } } if (!this->callbacks.empty() && trid >= 0) { if (this->callbacks.find(trid) != this->callbacks.end()) { (this->*(this->callbacks[trid].first))(args, trid, this->callbacks[trid].second); continue; } } if (isdigit(args[0][0])) this->showError(decimalFromString(args[0])); else this->dispatchCommand(args); } } void NotificationServerConnection::callback_NegotiateCVR(std::vector & args, int trid, void *data) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); connectinfo * info = (connectinfo *) data; this->removeCallback(trid); if (args.size() >= 3 && args[0] != "VER" || args[2] != "MSNP15") // if either *differs*... { this->myNotificationServer()->externalCallbacks.showError(NULL, "Protocol negotiation failed"); this->disconnect(); return; } std::ostringstream buf_; buf_ << "CVR " << this->trID << " 0x0409 winnt 5.1 i386 MSG80BETA 8.1.0178.00 MSMSGS " << info->username << "\r\n"; if (this->write(buf_) != buf_.str().size()) return; this->addCallback(&NotificationServerConnection::callback_RequestUSR, this->trID++, (void *) data); } void NotificationServerConnection::callback_TransferToSwitchboard(std::vector & args, int trid, void *data) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); SwitchboardServerConnection::AuthData *auth = static_cast(data); this->removeCallback(trid); if (args[0] != "XFR") { this->showError(decimalFromString(args[0])); this->disconnect(); delete auth; return; } auth->cookie = args[5]; auth->sessionID = ""; SwitchboardServerConnection *newconn = new SwitchboardServerConnection(*auth, *this); this->addSwitchboardConnection(newconn); std::pair server_address = splitServerAddress(args[3]); newconn->connect(server_address.first, server_address.second); delete auth; } void NotificationServerConnection::callback_RequestUSR(std::vector & args, int trid, void *data) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); connectinfo *info = (connectinfo *)data; this->removeCallback(trid); if (args.size() > 1 && args[0] != "CVR") // if*differs*... { this->myNotificationServer()->externalCallbacks.showError(NULL, "Protocol negotiation failed"); this->disconnect(); return; } std::ostringstream buf_; buf_ << "USR " << this->trID << " SSO I " << info->username << "\r\n"; if (this->write(buf_) != buf_.str().size()) return; this->addCallback(&NotificationServerConnection::callback_PassportAuthentication, this->trID++, (void *) data); } void NotificationServerConnection::callback_PassportAuthentication(std::vector & args, int trid, void * data) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); connectinfo * info; info=(connectinfo *)data; this->removeCallback(trid); if (isdigit(args[0][0])) { this->showError(decimalFromString(args[0])); this->disconnect(); return; } if (args.size() >= 4 && args[4].empty()) { this->disconnect(); return; } this->myNotificationServer()->externalCallbacks.getSecureHTTPProxy(); Soap *soapConnection = new Soap(*this); this->mdi = args[5]; soapConnection->setMBI(args[4]); soapConnection->getTickets(info->username,info->password,args[4]); delete info; info=NULL; } void NotificationServerConnection::gotTickets(Soap & soapConnection, std::vector sitesToAuthList) { std::ostringstream buf_; this->sitesToAuthList = sitesToAuthList; std::string token = sitesToAuthList[1].BinarySecurityToken; std::string binarysecret = sitesToAuthList[1].BinarySecret; this->token = token; buf_ << "USR " << this->trID << " SSO S " << token << " " << mdi_encrypt(binarysecret, mdi) << "\r\n"; if (this->write(buf_) != buf_.str().size()) return; this->addCallback(&NotificationServerConnection::callback_AuthenticationComplete, this->trID++, NULL); } void NotificationServerConnection::callback_AuthenticationComplete(std::vector & args, int trid, void * data) { this->assertConnectionStateIsAtLeast(NS_CONNECTED); this->removeCallback(trid); if (isdigit(args[0][0])) { this->showError(decimalFromString(args[0])); this->disconnect(); return; } server_email_verified = args[4]; } void NotificationServerConnection::get_oim(std::string id, bool markAsRead) { Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->getOIM(id,markAsRead); } void NotificationServerConnection::delete_oim(std::string id) { if(this->removingOIM) { DeletedQueuedOIMs.push_back(id); return; } this->removingOIM = true; Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->deleteOIM(id); } void NotificationServerConnection::send_oim(Soap::OIM oim) { // do not generate two lockkeys at the same time if(this->generatingLockkey) { SentQueuedOIMs.push_back(oim); return; } Soap *soapConnection = new Soap(*this, this->sitesToAuthList); SentQueuedOIMs.push_back(oim); this->generatingLockkey=true; soapConnection->generateLockkey(oim); } void NotificationServerConnection::gotOIM(Soap & soapConnection, bool success, std::string id, std::string message) { this->myNotificationServer()->externalCallbacks.gotOIM(this, success, id, message); } void NotificationServerConnection::gotOIMLockkey(Soap & soapConnection, std::string lockkey) { this->lockkey = lockkey; this->generatingLockkey = false; if(this->lockkey.empty()) { std::vector::iterator i = SentQueuedOIMs.begin(); for(; i != SentQueuedOIMs.end(); i++) { this->myNotificationServer()->externalCallbacks.gotOIMSendConfirmation(this, false, (*i).id); } SentQueuedOIMs.erase(SentQueuedOIMs.begin(), SentQueuedOIMs.end()); return; } sendQueuedOIMs(); } void NotificationServerConnection::gotOIMDeleteConfirmation(Soap & soapConnection, std::string id, bool deleted) { this->myNotificationServer()->externalCallbacks.gotOIMDeleteConfirmation(this, deleted, id); if(this->DeletedQueuedOIMs.empty()) { removingOIM = false; return; } else { Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->deleteOIM(DeletedQueuedOIMs.back()); DeletedQueuedOIMs.pop_back(); } } void NotificationServerConnection::gotOIMSendConfirmation(Soap & soapConnection, int id, bool sent) { if(!sent) this->lockkey.clear(); this->myNotificationServer()->externalCallbacks.gotOIMSendConfirmation(this, sent, id); } void NotificationServerConnection::sendQueuedOIMs() { std::vector::iterator i = SentQueuedOIMs.begin(); for(; i != SentQueuedOIMs.end(); i++) { Soap *soapConnection = new Soap(*this, this->sitesToAuthList); soapConnection->sendOIM((*i), this->lockkey); } SentQueuedOIMs.erase(SentQueuedOIMs.begin(), SentQueuedOIMs.end()); } bool NotificationServerConnection::change_DisplayPicture(std::string filename) { msnobj.delMSNObjectByType(3); if(!filename.empty()) msnobj.addMSNObject(filename,3); return true; } void NotificationServerConnection::gotChangeDisplayNameConfirmation(Soap & soapConnection, std::string displayName, bool changed) { if(changed) { this->myDisplayName = displayName; // server update OK, now change to the current session std::ostringstream buf_; buf_ << "PRP " << this->trID++ << " MFN " << encodeURL(displayName) << "\r\n"; write(buf_); } // TODO - raise an error if not changed } void NotificationServerConnection::gotAddContactToGroupConfirmation(Soap & soapConnection, bool added, std::string newVersion, std::string groupId, std::string contactId) { this->myNotificationServer()->externalCallbacks.addedContactToGroup(this, added, groupId, contactId); } void NotificationServerConnection::gotDelContactFromGroupConfirmation(Soap & soapConnection, bool removed, std::string newVersion, std::string groupId, std::string contactId) { this->myNotificationServer()->externalCallbacks.removedContactFromGroup(this, removed, groupId, contactId); } void NotificationServerConnection::gotAddGroupConfirmation(Soap & soapConnection, bool added, std::string newVersion, std::string groupName, std::string groupId) { this->myNotificationServer()->externalCallbacks.addedGroup(this, added, groupName, groupId); } void NotificationServerConnection::gotDelGroupConfirmation(Soap & soapConnection, bool removed, std::string newVersion, std::string groupId) { this->myNotificationServer()->externalCallbacks.removedGroup(this, removed, groupId); } void NotificationServerConnection::gotRenameGroupConfirmation(Soap & soapConnection, bool renamed, std::string newVersion, std::string newGroupName, std::string groupId) { this->myNotificationServer()->externalCallbacks.renamedGroup(this, renamed, newGroupName, groupId); } void NotificationServerConnection::gotAddContactToAddressBookConfirmation(Soap & soapConnection, bool added, std::string newVersion, std::string passport, std::string displayName, std::string guid) { this->myNotificationServer()->externalCallbacks.addedContactToAddressBook(this, added, passport, displayName, guid); if(added) { std::vector passport2 = splitString(passport, "@"); std::string user = passport2[0]; std::string domain = passport2[1]; // TODO - use xmlParser std::string payload3(""); std::ostringstream buf_3; buf_3 << "ADL " << this->trID++ << " " << payload3.length() << "\r\n"; buf_3 << payload3; write(buf_3); std::string payload2(""); std::ostringstream buf_2; buf_2 << "ADL " << this->trID++ << " " << payload2.length() << "\r\n"; buf_2 << payload2; write(buf_2); // the official client sends FQY std::string payload4(""); std::ostringstream buf_4; buf_4 << "FQY " << this->trID++ << " " << payload4.length() << "\r\n"; buf_4 << payload4; write(buf_4); } } void NotificationServerConnection::gotDelContactFromAddressBookConfirmation(Soap & soapConnection, bool removed, std::string newVersion, std::string contactId, std::string passport) { this->myNotificationServer()->externalCallbacks.removedContactFromAddressBook(this, removed, contactId, passport); if(removed) { std::vector passport2 = splitString(passport, "@"); std::string user = passport2[0]; std::string domain = passport2[1]; // TODO - use xmlParser std::string payload2(""); std::ostringstream buf_2; buf_2 << "RML " << this->trID++ << " " << payload2.length() << "\r\n"; buf_2 << payload2; write(buf_2); } } void NotificationServerConnection::gotEnableContactOnAddressBookConfirmation(Soap & soapConnection, bool disabled, std::string newVersion, std::string contactId, std::string passport) { this->myNotificationServer()->externalCallbacks.enabledContactOnAddressBook(this, disabled, contactId, passport); if(disabled) { std::vector passport2 = splitString(passport, "@"); std::string user = passport2[0]; std::string domain = passport2[1]; // TODO - use xmlParser std::string payload3(""); std::ostringstream buf_3; buf_3 << "ADL " << this->trID++ << " " << payload3.length() << "\r\n"; buf_3 << payload3; write(buf_3); } } void NotificationServerConnection::gotDisableContactOnAddressBookConfirmation(Soap & soapConnection, bool disabled, std::string newVersion, std::string contactId, std::string passport) { this->myNotificationServer()->externalCallbacks.disabledContactOnAddressBook(this, disabled, contactId); if(disabled) { std::vector passport2 = splitString(passport, "@"); std::string user = passport2[0]; std::string domain = passport2[1]; // TODO - use xmlParser std::string payload2(""); std::ostringstream buf_2; buf_2 << "RML " << this->trID++ << " " << payload2.length() << "\r\n"; buf_2 << payload2; write(buf_2); } } void NotificationServerConnection::gotAddContactToListConfirmation(Soap & soapConnection, bool added, std::string newVersion, std::string passport, MSN::ContactList list) { if(added) { std::vector passport2 = splitString(passport, "@"); std::string user = passport2[0]; std::string domain = passport2[1]; // TODO - use xmlParser std::string payload2(""); std::ostringstream buf_2; buf_2 << "ADL " << this->trID++ << " " << payload2.length() << "\r\n"; buf_2 << payload2; write(buf_2); this->myNotificationServer()->externalCallbacks.addedListEntry(this, list, passport, ""); } } void NotificationServerConnection::gotDelContactFromListConfirmation(Soap & soapConnection, bool deleted, std::string newVersion, std::string passport, MSN::ContactList list) { if(deleted) { std::vector passport2 = splitString(passport, "@"); std::string user = passport2[0]; std::string domain = passport2[1]; // TODO - use XMLParser std::string payload(""); std::ostringstream buf_; buf_ << "RML " << this->trID++ << " " << payload.length() << "\r\n"; buf_ << payload; write(buf_); this->myNotificationServer()->externalCallbacks.removedListEntry(this, list, passport); } } void NotificationServerConnection::setCapabilities(uint m_clientId) { this->m_clientId = m_clientId; } void NotificationServerConnection::getInboxUrl() { this->assertConnectionStateIsAtLeast(NS_CONNECTED); std::ostringstream buf_; buf_ << "URL " << this->trID << " INBOX\r\n"; write(buf_); this->addCallback(&NotificationServerConnection::callback_URL, this->trID++, NULL); } }