2010-09-24 08:48:01 -05:00
|
|
|
/*
|
|
|
|
* switchboardserver.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
|
|
|
|
*/
|
|
|
|
|
2012-02-25 21:35:45 -06:00
|
|
|
#include <switchboardserver.h>
|
|
|
|
#include <notificationserver.h>
|
|
|
|
#include <errorcodes.h>
|
|
|
|
#include <externals.h>
|
|
|
|
#include <util.h>
|
2010-09-24 08:48:01 -05:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
namespace MSN
|
|
|
|
{
|
|
|
|
std::map<std::string, void (SwitchboardServerConnection::*)(std::vector<std::string> &)> SwitchboardServerConnection::commandHandlers;
|
|
|
|
std::map<std::string, void (SwitchboardServerConnection::*)(std::vector<std::string> &, std::string, std::string)> SwitchboardServerConnection::messageHandlers;
|
|
|
|
|
|
|
|
SwitchboardServerConnection::SwitchboardServerConnection(AuthData & auth_, NotificationServerConnection & n)
|
|
|
|
: Connection(), auth(auth_), _connectionState(SB_DISCONNECTED), notificationServer(n)
|
|
|
|
{
|
|
|
|
registerCommandHandlers();
|
|
|
|
registerMessageHandlers();
|
|
|
|
}
|
|
|
|
|
|
|
|
SwitchboardServerConnection::~SwitchboardServerConnection()
|
|
|
|
{
|
|
|
|
if (this->connectionState() != SB_DISCONNECTED)
|
|
|
|
this->disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
Connection *SwitchboardServerConnection::connectionWithSocket(void * sock)
|
|
|
|
{
|
|
|
|
if (this->sock == sock)
|
|
|
|
return this;
|
|
|
|
|
|
|
|
/* std::list<FileTransferConnectionP2P *> & list2 = _fileTransferConnectionsP2P;
|
|
|
|
std::list<FileTransferConnectionP2P *>::iterator j = list2.begin();
|
|
|
|
|
|
|
|
for (; j != list2.end(); j++)
|
|
|
|
{
|
|
|
|
if ((*j)->sock == fd)
|
|
|
|
return *i;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::sendEmoticon(std::string alias, std::string file)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_READY);
|
|
|
|
|
|
|
|
myNotificationServer()->msnobj.addMSNObject(file,2);
|
|
|
|
std::string msnobject;
|
|
|
|
myNotificationServer()->msnobj.getMSNObjectXML(file, 2, msnobject);
|
|
|
|
|
|
|
|
std::ostringstream buf_, msg_;
|
|
|
|
msg_ << "MIME-Version: 1.0\r\n";
|
|
|
|
msg_ << "Content-Type: text/x-mms-emoticon\r\n\r\n";
|
|
|
|
msg_ << alias << "\t" << msnobject << "\t";
|
|
|
|
size_t msg_length = msg_.str().size();
|
|
|
|
|
|
|
|
buf_ << "MSG " << this->trID++ << " N " << (int) msg_length << "\r\n" << msg_.str();
|
|
|
|
write(buf_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::sendFile(MSN::fileTransferInvite ft)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_READY);
|
|
|
|
p2p.sendFile(*this,ft);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::addFileTransferConnectionP2P(FileTransferConnectionP2P *c)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
_fileTransferConnectionsP2P.push_back(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::removeFileTransferConnectionP2P(FileTransferConnectionP2P *c)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
_fileTransferConnectionsP2P.remove(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class _Tp>
|
|
|
|
class hasCookieOf
|
|
|
|
{
|
|
|
|
const std::string & cookie;
|
|
|
|
public:
|
|
|
|
hasCookieOf(const std::string & __i) : cookie(__i) {};
|
|
|
|
bool operator()(const _Tp &__x) { return __x->cookie == cookie; }
|
|
|
|
};
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::addCallback(SwitchboardServerCallback callback,
|
|
|
|
int trid, void *data)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTING);
|
|
|
|
this->callbacks[trid] = std::make_pair(callback, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::removeCallback(int trid)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTING);
|
|
|
|
this->callbacks.erase(trid);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::addP2PCallback(SwitchboardServerCallback2 callback,
|
|
|
|
int trid, unsigned int sessionID)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTING);
|
|
|
|
this->callbacks2[trid] = std::make_pair(callback, sessionID);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::removeP2PCallback(int trid)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTING);
|
|
|
|
this->callbacks2.erase(trid);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::registerMessageHandlers()
|
|
|
|
{
|
|
|
|
if (messageHandlers.size() == 0)
|
|
|
|
{
|
|
|
|
messageHandlers["text/plain"] = &SwitchboardServerConnection::message_plain;
|
|
|
|
messageHandlers["text/x-msmsgsinvite"] = &SwitchboardServerConnection::message_invitation;
|
|
|
|
messageHandlers["text/x-msmsgscontrol"] = &SwitchboardServerConnection::message_typing_user;
|
|
|
|
messageHandlers["application/x-msnmsgrp2p"] = &SwitchboardServerConnection::message_p2p;
|
|
|
|
messageHandlers["text/x-msnmsgr-datacast"] = &SwitchboardServerConnection::message_datacast;
|
|
|
|
messageHandlers["text/x-mms-emoticon"] = &SwitchboardServerConnection::message_emoticon;
|
|
|
|
messageHandlers["text/x-mms-animemoticon"] = &SwitchboardServerConnection::message_emoticon;
|
|
|
|
messageHandlers["image/gif"] = &SwitchboardServerConnection::message_ink;
|
|
|
|
messageHandlers["application/x-ms-ink"] = &SwitchboardServerConnection::message_ink;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::registerCommandHandlers()
|
|
|
|
{
|
|
|
|
if (commandHandlers.size() == 0)
|
|
|
|
{
|
|
|
|
commandHandlers["BYE"] = &SwitchboardServerConnection::handle_BYE;
|
|
|
|
commandHandlers["JOI"] = &SwitchboardServerConnection::handle_JOI;
|
|
|
|
commandHandlers["NAK"] = &SwitchboardServerConnection::handle_NAK;
|
|
|
|
commandHandlers["MSG"] = &SwitchboardServerConnection::handle_MSG;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::message_plain(std::vector<std::string> & args, std::string mime, std::string body)
|
|
|
|
{
|
|
|
|
Message msg = Message(body, mime);
|
|
|
|
|
|
|
|
this->myNotificationServer()->externalCallbacks.gotInstantMessage(this,args[1], decodeURL(args[2]), &msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::message_emoticon(std::vector<std::string> & args, std::string mime, std::string body)
|
|
|
|
{
|
|
|
|
std::vector<std::string> emoticons = splitString(body,"\t");
|
|
|
|
for(unsigned int i=0; i < emoticons.size(); )
|
|
|
|
{
|
|
|
|
// avoid errors with clients which do not respect the protocol
|
|
|
|
if(i+2 > emoticons.size()) return;
|
|
|
|
this->myNotificationServer()->externalCallbacks.gotEmoticonNotification(this,args[1], emoticons[i] , emoticons[i+1]);
|
|
|
|
i+=2; // move to the next one
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::message_invitation(std::vector<std::string> & args, std::string mime, std::string body)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::message_typing_user(std::vector<std::string> & args, std::string mime, std::string body)
|
|
|
|
{
|
|
|
|
this->myNotificationServer()->externalCallbacks.buddyTyping(this, args[1], decodeURL(args[2]));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::message_ink(std::vector<std::string> & args, std::string mime, std::string body)
|
|
|
|
{
|
|
|
|
std::string image = body.substr(body.find("base64:")+7);
|
|
|
|
this->myNotificationServer()->externalCallbacks.gotInk(this, args[1], image);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::message_p2p(std::vector<std::string> & args, std::string mime, std::string body)
|
|
|
|
{
|
|
|
|
p2p.handleP2Pmessage(*this,args,mime,body);
|
|
|
|
}
|
|
|
|
void SwitchboardServerConnection::message_datacast(std::vector<std::string> & args, std::string mime, std::string body)
|
|
|
|
{
|
|
|
|
Message::Headers headers = Message::Headers(body);
|
|
|
|
int id = decimalFromString(headers["ID"]);
|
|
|
|
switch(id)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
this->myNotificationServer()->externalCallbacks.gotNudge(this, args[1]);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
this->myNotificationServer()->externalCallbacks.gotWinkNotification(this, args[1], headers["Data"]);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
this->myNotificationServer()->externalCallbacks.gotVoiceClipNotification(this, args[1], headers["Data"]);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
this->myNotificationServer()->externalCallbacks.gotActionMessage(this, args[1], headers["Data"]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::dispatchCommand(std::vector<std::string> & args)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
std::map<std::string, void (SwitchboardServerConnection::*)(std::vector<std::string> &)>::iterator i = commandHandlers.find(args[0]);
|
|
|
|
if (i != commandHandlers.end())
|
|
|
|
(this->*commandHandlers[args[0]])(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
int SwitchboardServerConnection::sendMessage(const Message *msg)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_READY);
|
|
|
|
std::string s = msg->asString();
|
|
|
|
|
|
|
|
std::ostringstream buf_;
|
|
|
|
buf_ << "MSG " << this->trID << " A " << (int) s.size() << "\r\n" << s;
|
|
|
|
this->write(buf_);
|
|
|
|
this->addCallback(&SwitchboardServerConnection::callback_messageACK, this->trID, NULL);
|
|
|
|
return this->trID++;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SwitchboardServerConnection::sendMessage(const std::string & body)
|
|
|
|
{
|
|
|
|
Message msg(body, "MIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n");
|
|
|
|
return this->sendMessage(&msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::sendKeepAlive()
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_READY);
|
|
|
|
std::string s("MIME-Version: 1.0\r\nContent-Type: text/x-keepalive\r\n\r\n");
|
|
|
|
std::ostringstream buf_;
|
|
|
|
buf_ << "MSG " << this->trID++ << " U " << (int) s.size() << "\r\n" << s;
|
|
|
|
this->write(buf_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::handle_BYE(std::vector<std::string> & args)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
std::list<Passport> & list = this->users;
|
|
|
|
std::list<Passport>::iterator i;
|
|
|
|
|
|
|
|
this->myNotificationServer()->externalCallbacks.buddyLeftConversation(this, args[1]);
|
|
|
|
|
|
|
|
for (i = list.begin(); i != list.end(); i++)
|
|
|
|
{
|
|
|
|
if (*i == args[1])
|
|
|
|
{
|
|
|
|
list.remove(*i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->users.empty() || (args.size() > 3 && args[3] == "1"))
|
|
|
|
{
|
|
|
|
this->disconnect();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::handle_JOI(std::vector<std::string> & args)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
if (args[1] == this->auth.username)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (this->auth.sessionID.empty() && this->connectionState() == SB_WAITING_FOR_USERS)
|
|
|
|
this->setConnectionState(SB_READY);
|
|
|
|
|
|
|
|
this->users.push_back(args[1]);
|
|
|
|
this->myNotificationServer()->externalCallbacks.buddyJoinedConversation(this, args[1], decodeURL(args[2]), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::handle_NAK(std::vector<std::string> & args)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
this->myNotificationServer()->externalCallbacks.failedSendingMessage(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::handle_MSG(std::vector<std::string> & args)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_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);
|
|
|
|
|
|
|
|
std::string chunks = headers["Chunks"];
|
|
|
|
if(!chunks.empty())
|
|
|
|
{
|
|
|
|
// First packet of MultiPacket Data;
|
|
|
|
MultiPacketSession session;
|
|
|
|
std::string messageID = headers["Message-ID"];
|
|
|
|
session.chunks = decimalFromString(chunks);
|
|
|
|
session.mime = mime;
|
|
|
|
session.receivedChunks = 1;
|
|
|
|
session.body += body;
|
|
|
|
if(session.chunks != 1)
|
|
|
|
{
|
|
|
|
MultiPacketSessions[messageID] = session;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::string chunk = headers["Chunk"];
|
|
|
|
if(!chunk.empty())
|
|
|
|
{
|
|
|
|
// part of multipacket data
|
|
|
|
std::string messageID = headers["Message-ID"];
|
|
|
|
MultiPacketSession session = MultiPacketSessions[messageID];
|
|
|
|
session.body += body;
|
|
|
|
session.receivedChunks++;
|
|
|
|
if(session.chunks != session.receivedChunks)
|
|
|
|
{
|
|
|
|
MultiPacketSessions[messageID] = session;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MultiPacketSessions.erase(messageID);
|
|
|
|
body = session.body;
|
|
|
|
mime = session.mime;
|
|
|
|
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, void (SwitchboardServerConnection::*)(std::vector<std::string> &, std::string, std::string)>::iterator i = messageHandlers.find(contentType);
|
|
|
|
if (i != messageHandlers.end())
|
|
|
|
(this->*(messageHandlers[contentType]))(args, mime, body);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::sendAction(std::string action)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_READY);
|
|
|
|
std::ostringstream buf_, msg_;
|
|
|
|
msg_ << "MIME-Version: 1.0\r\n";
|
|
|
|
msg_ << "Content-Type: text/x-msnmsgr-datacast\r\n\r\n";
|
|
|
|
msg_ << "ID: 4\r\n";
|
|
|
|
msg_ << "Data: " << action << "\r\n" ;
|
|
|
|
size_t msg_length = msg_.str().size();
|
|
|
|
|
|
|
|
buf_ << "MSG " << this->trID++ << " U " << (int) msg_length << "\r\n" << msg_.str();
|
|
|
|
|
|
|
|
write(buf_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::sendVoiceClip(std::string msnobject)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_READY);
|
|
|
|
std::ostringstream buf_, msg_;
|
|
|
|
msg_ << "MIME-Version: 1.0\r\n";
|
|
|
|
msg_ << "Content-Type: text/x-msnmsgr-datacast\r\n\r\n";
|
|
|
|
msg_ << "ID: 3\r\n";
|
|
|
|
msg_ << "Data: " << msnobject << "\r\n\r\n";
|
|
|
|
size_t msg_length = msg_.str().size();
|
|
|
|
|
|
|
|
buf_ << "MSG " << this->trID++ << " N " << (int) msg_length << "\r\n" << msg_.str();
|
|
|
|
|
|
|
|
write(buf_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::sendWink(std::string msnobject)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_READY);
|
|
|
|
std::ostringstream buf_, msg_;
|
|
|
|
msg_ << "MIME-Version: 1.0\r\n";
|
|
|
|
msg_ << "Content-Type: text/x-msnmsgr-datacast\r\n\r\n";
|
|
|
|
msg_ << "ID: 2\r\n";
|
|
|
|
msg_ << "Data: " << msnobject << "\r\n\r\n";
|
|
|
|
size_t msg_length = msg_.str().size();
|
|
|
|
|
|
|
|
buf_ << "MSG " << this->trID++ << " N " << (int) msg_length << "\r\n" << msg_.str();
|
|
|
|
|
|
|
|
write(buf_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::sendNudge()
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_READY);
|
|
|
|
std::ostringstream buf_, msg_;
|
|
|
|
msg_ << "MIME-Version: 1.0\r\n";
|
|
|
|
msg_ << "Content-Type: text/x-msnmsgr-datacast\r\n\r\n";
|
|
|
|
msg_ << "ID: 1\r\n";
|
|
|
|
size_t msg_length = msg_.str().size();
|
|
|
|
|
|
|
|
buf_ << "MSG " << this->trID++ << " U " << (int) msg_length << "\r\n" << msg_.str();
|
|
|
|
|
|
|
|
write(buf_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::sendInk(std::string image)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_READY);
|
|
|
|
|
|
|
|
if(users.size() == 1)
|
|
|
|
{
|
|
|
|
p2p.sendInk(*this, image);
|
|
|
|
// return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string body("base64:"+image);
|
|
|
|
bool one_packet = false;
|
|
|
|
|
|
|
|
if(body.size() <= 1202) // if we need more than 1 packet, then use multipacket
|
|
|
|
one_packet = true ;
|
|
|
|
|
|
|
|
if(one_packet)
|
|
|
|
{
|
|
|
|
std::ostringstream buf_, msg_;
|
|
|
|
msg_ << "MIME-Version: 1.0\r\n";
|
|
|
|
msg_ << "Content-Type: image/gif\r\n\r\n";
|
|
|
|
msg_ << body;
|
|
|
|
|
|
|
|
size_t msg_length = msg_.str().size();
|
|
|
|
buf_ << "MSG " << this->trID++ << " N " << (int) msg_length << "\r\n" << msg_.str();
|
|
|
|
write(buf_);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::istringstream body_stream(body);
|
|
|
|
std::string messageid = new_branch();
|
|
|
|
std::vector<std::string> chunks;
|
|
|
|
// spliting the message
|
|
|
|
while(!body_stream.eof())
|
|
|
|
{
|
|
|
|
char *part = new char[1203];
|
|
|
|
memset(part,0,1203);
|
|
|
|
body_stream.read((char*)part, 1202);
|
|
|
|
std::string part1(part);
|
|
|
|
chunks.push_back(part1);
|
|
|
|
delete [] part;
|
|
|
|
}
|
|
|
|
|
|
|
|
// sending the first one
|
|
|
|
std::ostringstream buf_, msg_;
|
|
|
|
msg_ << "MIME-Version: 1.0\r\n";
|
|
|
|
msg_ << "Content-Type: image/gif\r\n";
|
|
|
|
msg_ << "Message-ID: " << messageid << "\r\n";
|
|
|
|
msg_ << "Chunks: " << chunks.size() << "\r\n\r\n";
|
|
|
|
msg_ << chunks.front();
|
|
|
|
|
|
|
|
size_t msg_length = msg_.str().size();
|
|
|
|
buf_ << "MSG " << this->trID++ << " N " << (int) msg_length << "\r\n" << msg_.str();
|
|
|
|
write(buf_);
|
|
|
|
|
|
|
|
std::vector<std::string>::iterator i = chunks.begin();
|
|
|
|
|
|
|
|
for(int num=0; i!=chunks.end(); i++, num++)
|
|
|
|
{
|
|
|
|
if(i == chunks.begin())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
std::ostringstream buf2_, msg2_;
|
|
|
|
msg2_ << "Message-ID: " << messageid << "\r\n";
|
|
|
|
msg2_ << "Chunk: " << num << "\r\n\r\n";
|
|
|
|
msg2_ << (*i);
|
|
|
|
|
|
|
|
size_t msg_length2 = msg2_.str().size();
|
|
|
|
buf2_ << "MSG " << this->trID++ << " N " << (int) msg_length2 << "\r\n" << msg2_.str();
|
|
|
|
write(buf2_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::sendTypingNotification()
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_READY);
|
|
|
|
std::ostringstream buf_, msg_;
|
|
|
|
msg_ << "MIME-Version: 1.0\r\n";
|
|
|
|
msg_ << "Content-Type: text/x-msmsgscontrol\r\n";
|
|
|
|
msg_ << "TypingUser: " << this->auth.username << "\r\n";
|
|
|
|
msg_ << "\r\n";
|
|
|
|
msg_ << "\r\n";
|
|
|
|
size_t msg_length = msg_.str().size();
|
|
|
|
|
|
|
|
buf_ << "MSG " << this->trID++ << " U " << (int) msg_length << "\r\n" << msg_.str();
|
|
|
|
|
|
|
|
write(buf_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::inviteUser(Passport userName)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_WAITING_FOR_USERS);
|
|
|
|
std::ostringstream buf_;
|
|
|
|
buf_ << "CAL " << this->trID++ << " " << userName << "\r\n";
|
|
|
|
write(buf_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::connect(const std::string & hostname, unsigned int port)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIs(SB_DISCONNECTED);
|
|
|
|
|
|
|
|
if ((this->sock = this->myNotificationServer()->externalCallbacks.connectToServer(hostname, port, &this->connected)) == NULL)
|
|
|
|
{
|
|
|
|
this->myNotificationServer()->externalCallbacks.showError(this, "Could not connect to switchboard server");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->myNotificationServer()->externalCallbacks.registerSocket(this->sock, 0, 1, false);
|
|
|
|
this->setConnectionState(SB_CONNECTING);
|
|
|
|
|
|
|
|
if (this->connected)
|
|
|
|
this->socketConnectionCompleted();
|
|
|
|
|
|
|
|
std::ostringstream buf_;
|
|
|
|
if (this->auth.sessionID.empty())
|
|
|
|
{
|
|
|
|
buf_ << "USR " << this->trID << " " << this->auth.username << " " << this->auth.cookie << "\r\n";
|
|
|
|
if (this->write(buf_) != buf_.str().size())
|
|
|
|
return;
|
|
|
|
this->addCallback(&SwitchboardServerConnection::callback_InviteUsers, this->trID, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
buf_ << "ANS " << this->trID << " " << this->auth.username << " " << this->auth.cookie << " " << this->auth.sessionID << "\r\n";
|
|
|
|
if (this->write(buf_) != buf_.str().size())
|
|
|
|
return;
|
|
|
|
this->myNotificationServer()->externalCallbacks.gotNewConnection(this);
|
|
|
|
this->addCallback(&SwitchboardServerConnection::callback_AnsweredCall, this->trID, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
this->trID++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::disconnect()
|
|
|
|
{
|
|
|
|
if (this->connectionState() == SB_DISCONNECTED)
|
|
|
|
return;
|
|
|
|
|
|
|
|
notificationServer.removeSwitchboardConnection(this);
|
|
|
|
this->myNotificationServer()->externalCallbacks.closingConnection(this);
|
|
|
|
|
|
|
|
std::list<FileTransferConnectionP2P *> list2 = _fileTransferConnectionsP2P;
|
|
|
|
std::list<FileTransferConnectionP2P *>::iterator j = list2.begin();
|
|
|
|
for (; j != list2.end(); j++)
|
|
|
|
{
|
|
|
|
removeFileTransferConnectionP2P(*j);
|
|
|
|
}
|
|
|
|
|
|
|
|
this->callbacks.clear();
|
|
|
|
Connection::disconnect();
|
|
|
|
this->setConnectionState(SB_DISCONNECTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::socketConnectionCompleted()
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIs(SB_CONNECTING);
|
|
|
|
Connection::socketConnectionCompleted();
|
|
|
|
this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock);
|
|
|
|
this->myNotificationServer()->externalCallbacks.registerSocket(this->sock, 1, 0, false);
|
|
|
|
this->setConnectionState(SB_WAITING_FOR_USERS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::handleIncomingData()
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
while (this->isWholeLineAvailable())
|
|
|
|
{
|
|
|
|
std::vector<std::string> args = this->getLine();
|
|
|
|
if (args[0] == "MSG" || args[0] == "NOT")
|
|
|
|
{
|
|
|
|
int dataLength = decimalFromString(args[3]);
|
|
|
|
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() > 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 (!this->callbacks2.empty() && trid > 0)
|
|
|
|
{
|
|
|
|
if (this->callbacks2.find(trid) != this->callbacks2.end())
|
|
|
|
{
|
|
|
|
(this->*(this->callbacks2[trid].first))(args, trid, this->callbacks2[trid].second);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isdigit(args[0][0]))
|
|
|
|
this->showError(decimalFromString(args[0]));
|
|
|
|
else
|
|
|
|
this->dispatchCommand(args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::callback_messageACK(std::vector<std::string> & args, int trid, void *)
|
|
|
|
{
|
|
|
|
this->removeCallback(trid);
|
|
|
|
this->myNotificationServer()->externalCallbacks.gotMessageSentACK(this, trid);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::callback_InviteUsers(std::vector<std::string> & args, int trid, void *)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
this->removeCallback(trid);
|
|
|
|
|
|
|
|
if (args.size() < 3)
|
|
|
|
{
|
|
|
|
this->showError(decimalFromString(args[0]));
|
|
|
|
this->disconnect();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(args[2] != "OK")
|
|
|
|
{
|
|
|
|
this->showError(decimalFromString(args[0]));
|
|
|
|
this->disconnect();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->myNotificationServer()->externalCallbacks.gotSwitchboard(this, this->auth.tag);
|
|
|
|
this->myNotificationServer()->externalCallbacks.gotNewConnection(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::callback_continueTransfer(std::vector<std::string> & args, int trid, unsigned int sessionID)
|
|
|
|
{
|
|
|
|
this->removeP2PCallback(trid);
|
|
|
|
p2p.handle_MSGACKReceived(*this,sessionID, args[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::fileTransferResponse(unsigned int sessionID, std::string filename, bool response)
|
|
|
|
{
|
|
|
|
p2p.handle_fileTransferResponse(*this,sessionID, filename, response);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::callback_AnsweredCall(std::vector<std::string> & args, int trid, void * data)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIs(SB_WAITING_FOR_USERS);
|
|
|
|
if (args.size() >= 3 && args[0] == "ANS" && args[2] == "OK")
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (isdigit(args[0][0]))
|
|
|
|
{
|
|
|
|
this->removeCallback(trid);
|
|
|
|
this->showError(decimalFromString(args[0]));
|
|
|
|
this->disconnect();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (args.size() >= 6 && args[0] == "IRO")
|
|
|
|
{
|
|
|
|
if (args[4] == this->auth.username)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this->users.push_back(args[4]);
|
|
|
|
this->myNotificationServer()->externalCallbacks.buddyJoinedConversation(this, args[4], decodeURL(args[5]), 1);
|
|
|
|
if (args[2] == args[3])
|
|
|
|
{
|
|
|
|
this->removeCallback(trid);
|
|
|
|
this->setConnectionState(SB_READY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::requestEmoticon(unsigned int id, std::string filename, std::string msnobject, std::string alias)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
p2p.requestEmoticon(*this,id, filename, msnobject, alias);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::requestWink(unsigned int id, std::string filename, std::string msnobject)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
p2p.requestWink(*this,id, filename, msnobject);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::requestVoiceClip(unsigned int id, std::string filename, std::string msnobject)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
p2p.requestVoiceClip(*this,id, filename, msnobject);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::requestDisplayPicture(unsigned int id, std::string filename, std::string msnobject)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
p2p.requestDisplayPicture(*this,id, filename, msnobject);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwitchboardServerConnection::cancelFileTransfer(unsigned int id)
|
|
|
|
{
|
|
|
|
this->assertConnectionStateIsAtLeast(SB_CONNECTED);
|
|
|
|
p2p.cancelTransfer(*this,id);
|
|
|
|
}
|
|
|
|
}
|