logo       

r359 - in trunk/msn: . impl: msg#00007

Subject: r359 - in trunk/msn: . impl
Author: bdash
Date: 2005-07-12 15:08:54 +1200 (Tue, 12 Jul 2005)
New Revision: 359

Added:
   trunk/msn/impl/
   trunk/msn/impl/authdata.h
   trunk/msn/impl/buddy.cpp
   trunk/msn/impl/buddy.h
   trunk/msn/impl/connection.cpp
   trunk/msn/impl/connection.h
   trunk/msn/impl/filetransfer.cpp
   trunk/msn/impl/filetransfer.h
   trunk/msn/impl/invitation.cpp
   trunk/msn/impl/invitation.h
   trunk/msn/impl/md5.cpp
   trunk/msn/impl/md5.h
   trunk/msn/impl/message.cpp
   trunk/msn/impl/message.h
   trunk/msn/impl/notificationserver.cpp
   trunk/msn/impl/notificationserver.h
   trunk/msn/impl/sstream_fix.h
   trunk/msn/impl/switchboardserver.cpp
   trunk/msn/impl/switchboardserver.h
Removed:
   trunk/msn/authdata.cpp
   trunk/msn/authdata.h
   trunk/msn/buddy.cpp
   trunk/msn/buddy.h
   trunk/msn/connection.cpp
   trunk/msn/connection.h
   trunk/msn/filetransfer.cpp
   trunk/msn/filetransfer.h
   trunk/msn/invitation.cpp
   trunk/msn/invitation.h
   trunk/msn/md5.cpp
   trunk/msn/md5.h
   trunk/msn/message.cpp
   trunk/msn/message.h
   trunk/msn/notificationserver.cpp
   trunk/msn/notificationserver.h
   trunk/msn/sstream_fix.h
   trunk/msn/switchboardserver.cpp
   trunk/msn/switchboardserver.h
Modified:
   trunk/msn/errorcodes.h
   trunk/msn/externals.h
   trunk/msn/msn.h
   trunk/msn/msntest.cpp
   trunk/msn/util.cpp
Log:
Beginnings of huge restructuring.  It compiles... due to the 500+ lines that 
got commented out.

Deleted: trunk/msn/authdata.cpp
===================================================================
--- trunk/msn/authdata.cpp      2005-07-11 23:42:29 UTC (rev 358)
+++ trunk/msn/authdata.cpp      2005-07-12 03:08:54 UTC (rev 359)
@@ -1,24 +0,0 @@
-/*
- * authdata.cpp
- * libmsn
- *
- * Created by Mark Rowe on Mon Mar 22 2004.
- * Copyright (c) 2004 Mark Rowe. 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 <msn/authdata.h>
-

Deleted: trunk/msn/authdata.h
===================================================================
--- trunk/msn/authdata.h        2005-07-11 23:42:29 UTC (rev 358)
+++ trunk/msn/authdata.h        2005-07-12 03:08:54 UTC (rev 359)
@@ -1,44 +0,0 @@
-#ifndef __msn_authdata_h__
-#define __msn_authdata_h__
-
-/*
- * authdata.h
- * libmsn
- *
- * Created by Mark Rowe on Mon Mar 22 2004.
- * Copyright (c) 2004 Mark Rowe. 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 <string>
-#include <msn/passport.h>
-#include <msn/uncopyable.h>
-
-namespace MSN
-{
-    class AuthData : private Uncopyable
-    {
-public:
-        Passport username;
-        
-        AuthData(const Passport & username_) : username(username_) {};
-        AuthData(const AuthData & auth_) : username(auth_.username) {};
-        virtual ~AuthData() {};
-        
-        AuthData &operator=(const AuthData & auth_) { username = 
auth_.username; return *this; };
-    };
-}
-#endif

Deleted: trunk/msn/buddy.cpp
===================================================================
--- trunk/msn/buddy.cpp 2005-07-11 23:42:29 UTC (rev 358)
+++ trunk/msn/buddy.cpp 2005-07-12 03:08:54 UTC (rev 359)
@@ -1,74 +0,0 @@
-/*
- * buddy.cpp
- * libmsn
- *
- * Created by Mark Rowe on Mon Apr 19 2004.
- * Copyright (c) 2004 Mark Rowe. 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 <msn/buddy.h>
-#include <cassert>
-
-namespace MSN
-{
-    std::string buddyStatusToString(BuddyStatus state)
-    {
-        switch (state)
-        {
-            case STATUS_AVAILABLE:
-                return "NLN";
-            case STATUS_BUSY:
-                return "BSY";
-            case STATUS_IDLE:
-                return "IDL";
-            case STATUS_BERIGHTBACK:
-                return "BRB";
-            case STATUS_AWAY:
-                return "AWY";
-            case STATUS_ONTHEPHONE:
-                return "PHN";
-            case STATUS_OUTTOLUNCH:
-            return "LUN";
-            case STATUS_INVISIBLE:
-                return "HDN";
-            default:
-                assert(false);
-        }
-    }
-    
-    BuddyStatus buddyStatusFromString(std::string state)
-    {
-        if (state == "NLN")
-            return STATUS_AVAILABLE;
-        else if (state == "BSY")
-            return STATUS_BUSY;
-        else if (state == "IDL")
-            return STATUS_IDLE;
-        else if (state == "BRB")
-            return STATUS_BERIGHTBACK;
-        else if (state == "AWY")
-            return STATUS_AWAY;
-        else if (state == "PHN")
-            return STATUS_ONTHEPHONE;
-        else if (state == "LUN")
-            return STATUS_OUTTOLUNCH;
-        else if (state == "HDN")
-            return STATUS_INVISIBLE;
-        else
-            throw std::runtime_error("Unknown status!");
-    }
-}

Deleted: trunk/msn/buddy.h
===================================================================
--- trunk/msn/buddy.h   2005-07-11 23:42:29 UTC (rev 358)
+++ trunk/msn/buddy.h   2005-07-12 03:08:54 UTC (rev 359)
@@ -1,163 +0,0 @@
-#ifndef __msn_buddy_h__
-#define __msn_buddy_h__
-
-/*
- * buddy.h
- * libmsn
- *
- * Created by Mark Rowe on Mon Apr 19 2004.
- * Copyright (c) 2004 Mark Rowe. 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 <string>
-#include <list>
-#include <msn/passport.h>
-#include <msn/uncopyable.h>
-
-namespace MSN
-{
-    /** The online state of a buddy.
-    */
-    
-    enum BuddyStatus
-    {
-        STATUS_AVAILABLE, /**< NLN */
-        STATUS_BUSY, /**< BSY */
-        STATUS_IDLE, /**< IDL */
-        STATUS_BERIGHTBACK, /**< BRB */
-        STATUS_AWAY, /**< AWY */
-        STATUS_ONTHEPHONE, /**< PHN */
-        STATUS_OUTTOLUNCH, /**< OTL */
-        STATUS_INVISIBLE /**< HDN */
-    };
-    
-    /** Maps the BuddyStatus @a s into the MSN protocol-level name for the 
status */
-    std::string buddyStatusToString(BuddyStatus s);
-    
-    /** Maps the MSN protocol-level status name @a s into the corresponding 
BuddyStatus value */
-    BuddyStatus buddyStatusFromString(std::string s);
-    
-    class Group;
-    
-    /** The Buddy class contains information about a member of a buddy list.
-     *
-     *  Each Buddy is made up of their passport address (@a userName),
-     *  user-visible display name (@a friendlyName), zero or more @a 
phoneNumbers,
-     *  and zero or more @a groups on the buddy list that they belong to.
-     *
-     *  It is only currently used during MSN::Callbacks::gotBuddyListInfo to
-     *  store contact information about a buddy that was retrieved during
-     *  the buddy list synchronisation process.
-     */
-    class Buddy : private Uncopyable
-    {
-        /** @todo  BPR's need to be handled at any time, not just when 
syncing. */
-public:
-        /** The PhoneNumber class contains information about a single phone 
number
-         *  that is retrieved during the buddy list synchronisation process.
-         */
-        class PhoneNumber : private Uncopyable
-        {
-public:
-            /** The name of this phone number.
-             *
-             *  @todo Should this be an enumeration containing the possible
-             *        types of phone number?
-             */
-            std::string title;
-            
-            /** The phone number */
-            std::string number;
-            
-            /** @todo Document me! */
-            bool enabled;
-            
-            /** Initialize a PhoneNumber with the given @a title_ and phone @a 
number_ */
-            PhoneNumber(std::string title_, std::string number_, bool 
enabled_=true)
-                : title(title_), number(number_), enabled(enabled_) {};
-            
-            PhoneNumber(const PhoneNumber & phoneNumber_) : 
title(phoneNumber_.title), number(phoneNumber_.number), 
enabled(phoneNumber_.enabled) {};
-            PhoneNumber &operator=(const PhoneNumber & phoneNumber_)
-            {
-                title = phoneNumber_.title;
-                number = phoneNumber_.number;
-                enabled = phoneNumber_.enabled;
-                return *this;
-            }
-        };
-        
-        /** Their passport address */
-        Passport userName;
-        
-        /** Their friendly name */
-        std::string friendlyName;
-        
-        /** A list of phone numbers related to this buddy */
-        std::list<Buddy::PhoneNumber> phoneNumbers;
-        
-        /** A list of Group's that this buddy is a member of */
-        std::list<Group *> groups;
-        
-        /** Initialize the Buddy with the given @a userName_ and @a 
friendlyName_ */
-        Buddy(Passport userName_, std::string friendlyName_) :
-            userName(userName_), friendlyName(friendlyName_),
-            phoneNumbers(), groups() {};
-        
-        Buddy(const Buddy & buddy_) : userName(buddy_.userName), 
friendlyName(buddy_.friendlyName), phoneNumbers(buddy_.phoneNumbers), 
groups(buddy_.groups) {};
-        Buddy &operator=(const Buddy & buddy_)
-        {
-            userName = buddy_.userName;
-            friendlyName = buddy_.friendlyName;
-            phoneNumbers = buddy_.phoneNumbers;
-            groups = buddy_.groups;
-            return *this;
-        }
-        
-        /** Compare two buddies for equality based on userName */
-        bool const operator==(const Buddy &other) { return userName == 
other.userName; }
-    };
-    
-    /** The Group class represents a group of contacts on the buddy list.
-     *
-     *  Each group is represented by an integer @a groupID and has a 
user-visible
-     *  @a name.
-     */
-    class Group : private Uncopyable
-    {
-public:
-        /** The group ID */
-        int groupID;
-        
-        /** The group name */
-        std::string name;
-        
-        /** A list of buddies in the group */
-        std::list<Buddy *> buddies;
-        
-        /** Initialize a Group with the given @a groupID_ and @a name_ */
-        Group(int groupID_, std::string name_)
-            : groupID(groupID_), name(name_), buddies() {};
-        
-        /** Initialize an empty, invalid group. */
-        Group() : groupID(-1), name("INVALID"), buddies() {};
-        
-        Group(const Group & group_) : groupID(group_.groupID), 
name(group_.name), buddies(group_.buddies) {};
-        Group &operator=(const Group & group_) { groupID = group_.groupID; 
name = group_.name; buddies = group_.buddies; return *this; }
-    };
-}
-
-#endif

Deleted: trunk/msn/connection.cpp
===================================================================
--- trunk/msn/connection.cpp    2005-07-11 23:42:29 UTC (rev 358)
+++ trunk/msn/connection.cpp    2005-07-12 03:08:54 UTC (rev 359)
@@ -1,313 +0,0 @@
-/*
- * connection.cpp
- * libmsn
- *
- * Created by Mark Rowe on Mon Mar 22 2004.
- * Copyright (c) 2004 Mark Rowe. 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 <msn/connection.h>
-#include <msn/errorcodes.h>
-#include <msn/util.h>
-#include <msn/passport.h>
-#include <msn/externals.h>
-#include <msn/notificationserver.h>
-
-#ifndef WIN32
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#else
-#include <winsock.h>
-#include <io.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <cerrno>
-#include <time.h>
-#include <cassert>
-
-namespace MSN
-{
-    std::map<std::string, void (Connection::*)(std::vector<std::string> &, 
std::string, std::string)> Connection::messageHandlers;
-    static std::vector<std::string> errors;
-
-    Connection::Connection() 
-        : sock(0), connected(false), trID(1), readBuffer(), writeBuffer()
-    {
-        srand((unsigned int) time(NULL));
-
-        if (errors.size() != 0)
-        {
-            assert(errors.size() == 1000);
-        }
-        else
-        {
-            errors.resize(1000);
-            for (int a = 0; a < 1000; a++)
-            {
-                errors[a] = "Unknown error code";
-            }
-            
-            errors[200] = "Syntax error";
-            errors[201] = "Invalid parameter";
-            errors[205] = "Invalid user";
-            errors[206] = "Domain name missing from username";
-            errors[207] = "Already logged in";
-            errors[208] = "Invalid username";
-            errors[209] = "Invalid friendly name";
-            errors[210] = "List full";
-            errors[215] = "This user is already on this list or in this 
session";
-            errors[216] = "Not on list";
-            errors[218] = "Already in this mode";
-            errors[219] = "This user is already in the opposite list";
-            errors[280] = "Switchboard server failed";
-            errors[281] = "Transfer notification failed";
-            errors[300] = "Required fields missing";
-            errors[302] = "Not logged in";
-            errors[500] = "Internal server error";
-            errors[501] = "Database server error";
-            errors[510] = "File operation failed at server";
-            errors[520] = "Memory allocation failed on server";
-            errors[600] = "The server is too busy";
-            errors[601] = "The server is unavailable";
-            errors[602] = "A Peer Notification Server is down";
-            errors[603] = "Database connection failed";
-            errors[604] = "Server going down for maintenance";
-            errors[707] = "Server failed to create connection";
-            errors[711] = "Blocking write failed on server";
-            errors[712] = "Session overload on server";
-            errors[713] = "You have been too active recently. Slow down!";
-            errors[714] = "Too many sessions open";
-            errors[715] = "Not expected";
-            errors[717] = "Bad friend file on server";
-            errors[911] = "Authentication failed. Check that you typed your 
username and password correctly.";
-            errors[913] = "This action is not allowed while you are offline";
-            errors[920] = "This server is not accepting new users";            
-        }
-
-        if (messageHandlers.size() == 0)
-        {
-            messageHandlers["text/plain"]                            = 
&Connection::message_plain;
-            messageHandlers["text/x-msmsgsinitialemailnotification"] = 
&Connection::message_initial_email_notification;
-            messageHandlers["text/x-msmsgsemailnotification"]        = 
&Connection::message_email_notification;
-            messageHandlers["text/x-msmsgsinvite"]                   = 
&Connection::message_invitation;
-            messageHandlers["text/x-msmsgscontrol"]                  = 
&Connection::message_typing_user;            
-        }
-    }
-    
-    Connection::~Connection() {}
-    
-    void Connection::disconnect()
-    {
-        
this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock);
-        ::close(this->sock);
-        this->sock = -1;
-        this->writeBuffer.erase();
-        this->readBuffer.erase();
-        this->trID = 1;
-    }
-    
-    std::vector<std::string> Connection::getLine()
-    {
-        assert(this->isWholeLineAvailable());
-        std::string s = this->readBuffer.substr(0, 
this->readBuffer.find("\r\n"));
-        this->myNotificationServer()->externalCallbacks.log(0, (s + 
"\n").c_str());
-        return splitString(s, " ");
-    }
-    
-    bool Connection::isWholeLineAvailable()
-    {
-        return this->readBuffer.find("\r\n") != std::string::npos;
-    }
-    
-    void Connection::errorOnSocket(int errno_)
-    {
-        this->myNotificationServer()->externalCallbacks.showError(this, 
strerror(errno_));
-        this->disconnect();
-    }
-    
-    void Connection::socketConnectionCompleted()
-    {
-        this->connected = true;
-        
-        // We know that we are connected, so this will try writing to the 
network.
-        size_t writtenLength = this->write(this->writeBuffer, 1);
-        this->writeBuffer = this->writeBuffer.substr(writtenLength);
-    }
-        
-    size_t Connection::write(std::string s, bool log) throw 
(std::runtime_error)
-    {
-        if (! this->connected)
-            this->writeBuffer.append(s);
-        else
-        {
-            if (log)
-                this->myNotificationServer()->externalCallbacks.log(1, 
s.c_str());
-            
-            size_t written = 0;
-            while (written < s.size())
-            {
-                size_t newWritten = ::send(this->sock, 
s.substr(written).c_str(), (int) (s.size() - written), 0);
-                if (newWritten <= 0)
-                {
-                    if (errno == EAGAIN)
-                        continue;
-                    else
-                        break;
-                }
-                written += newWritten;
-            }
-            if (written != s.size())
-            {
-                this->errorOnSocket(errno);
-                return written;
-            }
-        }
-        return s.size();
-    }
-    
-    size_t Connection::write(std::ostringstream & ss, bool log) throw 
(std::runtime_error)
-    {
-        std::string s = ss.str();
-        size_t result = write(s, log);
-        return result;        
-    }
-        
-    void Connection::dataArrivedOnSocket()
-    {
-        char tempReadBuffer[8192];
-        int amountRead = ::recv(this->sock, &tempReadBuffer[0], 8192, 0);
-        if (amountRead < 0)
-        {
-            if (errno == EAGAIN)
-                return;
-            
-            // We shouldn't get EAGAIN here because dataArrivedOnSocket
-            // is only called when select/poll etc has told us that
-            // the socket is readable.
-            // assert(errno != EAGAIN);
-            
-            this->myNotificationServer()->externalCallbacks.showError(this, 
strerror(errno));                
-            this->disconnect();            
-        }
-        else if (amountRead == 0)
-        {
-            this->myNotificationServer()->externalCallbacks.showError(this, 
"Connection closed by remote endpoint.");
-            this->disconnect();
-        }
-        else
-        {
-            this->readBuffer += std::string(tempReadBuffer, amountRead);
-            try
-            {
-                handleIncomingData();
-            }
-            catch (std::exception & e)
-            {
-                
this->myNotificationServer()->externalCallbacks.showError(this, e.what());
-            }
-        }
-    }
-    
-    void Connection::handle_MSG(std::vector<std::string> & args)
-    {
-        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(mime);
-        contentType = headers["Content-Type"];
-        
-        if ((tmp = contentType.find("; charset")) != std::string::npos)
-            contentType = contentType.substr(0, tmp);
-        
-        std::map<std::string, void (Connection::*)(std::vector<std::string> &, 
std::string, std::string)>::iterator i = messageHandlers.find(contentType);
-        if (i != messageHandlers.end())
-            (this->*(messageHandlers[contentType]))(args, mime, body);
-    }
-    
-    void Connection::message_plain(std::vector<std::string> & args, 
std::string mime, std::string body)
-    {
-        Message msg(body, mime);
-        
-        
this->myNotificationServer()->externalCallbacks.gotInstantMessage(static_cast<SwitchboardServerConnection
 *>(this),
-                               args[1], decodeURL(args[2]), &msg);
-    }
-    
-    void 
Connection::message_initial_email_notification(std::vector<std::string> & 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(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 Connection::message_email_notification(std::vector<std::string> & 
args, std::string mime, std::string body)
-    {
-        // New email notifications body is a set of MIME headers
-        Message::Headers headers(body);
-        
-        std::string from = headers["From-Addr"];
-        std::string subject = headers["Subject"];
-        
-        
this->myNotificationServer()->externalCallbacks.gotNewEmailNotification(this, 
from, subject);
-    }
-
-    
-    void Connection::message_invitation(std::vector<std::string> & args, 
std::string mime, std::string body)
-    {
-        static_cast<SwitchboardServerConnection 
*>(this)->handleInvite(args[1], decodeURL(args[2]), mime, body);
-    }
-
-    void Connection::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 Connection::showError(int errorCode)
-    {
-        std::ostringstream buf_;
-        buf_ << "Error code: " << errorCode << " (" << errors[errorCode] << 
")";
-        this->myNotificationServer()->externalCallbacks.showError(this, 
buf_.str());        
-    }
-}

Deleted: trunk/msn/connection.h
===================================================================
--- trunk/msn/connection.h      2005-07-11 23:42:29 UTC (rev 358)
+++ trunk/msn/connection.h      2005-07-12 03:08:54 UTC (rev 359)
@@ -1,184 +0,0 @@
-#ifndef __msn_connection_h__
-#define __msn_connection_h__
-
-/*
- * connection.h
- * libmsn
- *
- * Created by Mark Rowe on Mon Mar 22 2004.
- * Copyright (c) 2004 Mark Rowe. 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 <string>
-#include <list>
-#include <vector>
-#include <map>
-#include <msn/sstream_fix.h>
-#include <msn/uncopyable.h>
-#include <stdexcept>
-
-namespace MSN
-{
-    class callback;
-    class Message;
-    class Passport;
-    class NotificationServerConnection;
-    class SwitchboardServerConnection;
-    class FileTransferConnection;
-    class FileTransferInvitation;
-    
-    /** An abstract base class that represents a connection to another 
computer.
-     *
-     *  Connection provides an interface and some functionality that is common
-     *  to notification, switchboard and file transfer connections.
-     *
-     * @todo Connection should have a read buffer that stores all incoming data
-     *       that is waiting to be processed.  Member functions should use that
-     *       for necessary data, and <em>not</em> call Connection::readExactly.
-     */
-    class Connection : private Uncopyable
-    {
-      friend class SwitchboardServerConnection;
-      friend class NotificationServerConnection;
-      friend class FileTransferConnection;
-      friend class FileTransferInvitation;
-      
-public:
-        /** The socket which connects this Connection to another computer
-         *
-         * @deprecated  In the future, this member will be made private.  Any
-         *              functions that access this member should be converted 
to
-         *              member functions of a subclass.
-         */
-        int sock;
-        
-        /** Indicates whether a connection has been established.
-         *
-         * @todo  This is currently public only because 
FileTransferInvitation::receiveFile
-         *        accesses it.  It should be made protected in the future, and
-         *        FileTransferInvitation refactored to remove it's dependency 
on
-         *        this attribute.
-         */
-        bool connected;
-        
-private:
-        /** The transaction ID of the next command to be sent.
-         */
-        int trID;
-        
-        std::string readBuffer;
-public: 
-        Connection();
-        virtual ~Connection();
-        
-        /** Connect ourself to @a hostname on @a port.
-         */
-        virtual void connect(const std::string & hostname, unsigned int port) 
= 0;
-        
-        /** Close the current connection.
-         *
-         * This should not be called if the connection is already disconnected.
-         */
-        virtual void disconnect() = 0;
-        
-        /** @name External Socket Hooks
-         *  
-         *  These members should be called whenever an appropriate socket event
-         *  occurs.
-         */
-        /** @{ */
-        
-        /** New data is available on the connection.
-         */
-        virtual void dataArrivedOnSocket();
-        
-        /** The connection has been established.
-         */
-        virtual void socketConnectionCompleted();
-        
-        /** The socket is ready for data to be written to it.
-         */
-        virtual void socketIsWritable() {};
-        
-        /** An error has occurred on the socket.
-         */
-        virtual void errorOnSocket(int errno_);
-        /** @} */
-                
-        /** Notify the calling library that an error with code @a errorCode has
-         *  occured.
-         */
-        void showError(int errorCode);
-        
-        /** Is this Connection connected to a remote endpoint?
-         */
-        bool isConnected() { return this->connected; };
-        
-        /** Retrieve the parent NotificationServerConnection from this 
connection */
-        virtual NotificationServerConnection *myNotificationServer() = 0;
-private:
-         /** Process a @c <code>MSG</code> command.
-          *
-          *  This method will read the remaining message data from the network
-          *  and then delegates to private @c message_* functions based on the
-          *  @c Content-Type header found in the message.
-          */
-        void handle_MSG(std::vector<std::string> & args);
-        
-        virtual void handleIncomingData() = 0;
-        
-        /** Dispatch a command to its appropriate handler routines based on @a 
args.
-         * 
-         *  @param  args  A vector of strings containing arguments, returned 
from readLine.
-         */
-        virtual void dispatchCommand(std::vector<std::string> & args) = 0;
-
-        /** Read a line from the network and split it into its components.
-         *
-         *  MSN commands and their arguments are separated by white space.
-         */
-        std::vector<std::string> getLine();
-        
-        bool isWholeLineAvailable();
-        bool bytesAvailable();
-        
-        /** Write a string to the connection.
-         *
-         */
-        virtual size_t write(std::string s, bool log=true) throw 
(std::runtime_error);
-        
-        /** Write the contents of a stringstream to the connection.
-         *    
-         * @param  s    The stringstream to write.
-         * @param  log  Should we log this output to the console.
-         *
-         * write will buffer the output if a connection has not yet been 
established.
-         * In this case, the data will be written as soon as a connection is 
-         * established.
-         */
-        virtual size_t write(std::ostringstream & s, bool log=true) throw 
(std::runtime_error);
-                
-        std::string writeBuffer;
-        static std::map<std::string, void 
(Connection::*)(std::vector<std::string> &, std::string, std::string)> 
messageHandlers;
-        void message_plain(std::vector<std::string> & args, std::string mime, 
std::string body);
-        void message_initial_email_notification(std::vector<std::string> & 
args, std::string mime, std::string body);
-        void message_email_notification(std::vector<std::string> & args, 
std::string mime, std::string body);
-        void message_invitation(std::vector<std::string> & args, std::string 
mime, std::string body);
-        void message_typing_user(std::vector<std::string> & args, std::string 
mime, std::string body);
-    };
-}
-#endif

Modified: trunk/msn/errorcodes.h
===================================================================
--- trunk/msn/errorcodes.h      2005-07-11 23:42:29 UTC (rev 358)
+++ trunk/msn/errorcodes.h      2005-07-12 03:08:54 UTC (rev 359)
@@ -24,8 +24,6 @@
  */
 
 #include <string>
-#include <list>
-#include <msn/switchboardserver.h>
 
 /** \mainpage libmsn 3.2 Reference
  *

Modified: trunk/msn/externals.h
===================================================================
--- trunk/msn/externals.h       2005-07-11 23:42:29 UTC (rev 358)
+++ trunk/msn/externals.h       2005-07-12 03:08:54 UTC (rev 359)
@@ -24,11 +24,16 @@
  */
 
 #include <msn/buddy.h>
+#include <msn/passport.h>
 #include <msn/uncopyable.h>
 
 namespace MSN
 {
     class ListSyncInfo;
+    class NotificationServerConnection;
+    class SwitchboardServerConnection;
+    class Message;
+    class FileTransferInvitation;
     
     class Callbacks : private Uncopyable
     {
@@ -38,50 +43,50 @@
         virtual void registerSocket(int s, int read, int write) = 0;
         virtual void unregisterSocket(int s) = 0;
         
-        virtual void showError(MSN::Connection * conn, std::string msg) = 0;
+        virtual void showError(MSN::Connection * conn, const std::string & 
msg) = 0;
         
-        virtual void buddyChangedStatus(MSN::Connection * conn, MSN::Passport 
buddy, std::string friendlyname, MSN::BuddyStatus state) = 0;
-        virtual void buddyOffline(MSN::Connection * conn, MSN::Passport buddy) 
= 0;
+        virtual void buddyChangedStatus(MSN::Connection * conn, const 
MSN::Passport & buddy, const std::string & friendlyname, MSN::BuddyStatus 
state) = 0;
+        virtual void buddyOffline(MSN::Connection * conn, const MSN::Passport 
& buddy) = 0;
         
-        virtual void log(int writing, const char* buf) = 0;
+        virtual void log(int writing, const std::string & message) = 0;
         
-        virtual void gotFriendlyName(MSN::Connection * conn, std::string 
friendlyname) = 0;
+        virtual void gotFriendlyName(MSN::Connection * conn, const std::string 
& friendlyname) = 0;
         virtual void gotBuddyListInfo(MSN::NotificationServerConnection * 
conn, MSN::ListSyncInfo * data) = 0;
         virtual void gotLatestListSerial(MSN::Connection * conn, int serial) = 
0;
         virtual void gotGTC(MSN::Connection * conn, char c) = 0;
         virtual void gotBLP(MSN::Connection * conn, char c) = 0;
         
-        virtual void gotNewReverseListEntry(MSN::Connection * conn, 
MSN::Passport buddy, std::string friendlyname) = 0;
+        virtual void gotNewReverseListEntry(MSN::Connection * conn, const 
MSN::Passport & buddy, const std::string & friendlyname) = 0;
         
-        virtual void addedListEntry(MSN::Connection * conn, std::string list, 
MSN::Passport buddy, int groupID) = 0;
+        virtual void addedListEntry(MSN::Connection * conn, const std::string 
& list, const MSN::Passport & buddy, int groupID) = 0;
         
-        virtual void removedListEntry(MSN::Connection * conn, std::string 
list, MSN::Passport buddy, int groupID) = 0;
+        virtual void removedListEntry(MSN::Connection * conn, const 
std::string & list, const MSN::Passport & buddy, int groupID) = 0;
         
-        virtual void addedGroup(MSN::Connection * conn, std::string groupName, 
int groupID) = 0;
+        virtual void addedGroup(MSN::Connection * conn, const std::string & 
groupName, int groupID) = 0;
         virtual void removedGroup(MSN::Connection * conn, int groupID) = 0;
-        virtual void renamedGroup(MSN::Connection * conn, int groupID, 
std::string newGroupName) = 0;
+        virtual void renamedGroup(MSN::Connection * conn, int groupID, const 
std::string & newGroupName) = 0;
         
         virtual void gotSwitchboard(MSN::SwitchboardServerConnection * conn, 
const void * tag) = 0;
         
-        virtual void buddyJoinedConversation(MSN::SwitchboardServerConnection 
* conn, MSN::Passport buddy, std::string friendlyname, int is_initial) = 0;
+        virtual void buddyJoinedConversation(MSN::SwitchboardServerConnection 
* conn, const MSN::Passport & buddy, const std::string & friendlyname, int 
is_initial) = 0;
         
-        virtual void buddyLeftConversation(MSN::SwitchboardServerConnection * 
conn, MSN::Passport buddy) = 0;
+        virtual void buddyLeftConversation(MSN::SwitchboardServerConnection * 
conn, const MSN::Passport & buddy) = 0;
         
-        virtual void gotInstantMessage(MSN::SwitchboardServerConnection * 
conn, MSN::Passport buddy, std::string friendlyname, MSN::Message * msg) = 0;
+        virtual void gotInstantMessage(MSN::SwitchboardServerConnection * 
conn, const MSN::Passport & buddy, const std::string & friendlyname, 
MSN::Message * msg) = 0;
         
         virtual void failedSendingMessage(MSN::Connection * conn) = 0;
         
-        virtual void buddyTyping(MSN::Connection * conn, MSN::Passport buddy, 
std::string friendlyname) = 0;
+        virtual void buddyTyping(MSN::Connection * conn, const MSN::Passport & 
buddy, const std::string & friendlyname) = 0;
         
         virtual void gotInitialEmailNotification(MSN::Connection * conn, int 
unread_inbox, int unread_folders) = 0;
         
-        virtual void gotNewEmailNotification(MSN::Connection * conn, 
std::string from, std::string subject) = 0;
+        virtual void gotNewEmailNotification(MSN::Connection * conn, const 
std::string & from, const std::string & subject) = 0;
         
-        virtual void gotFileTransferInvitation(MSN::Connection * conn, 
MSN::Passport buddy, std::string friendlyname, MSN::FileTransferInvitation * 
inv) = 0;
+        virtual void gotFileTransferInvitation(MSN::Connection * conn, const 
MSN::Passport & buddy, const std::string & friendlyname, 
MSN::FileTransferInvitation * inv) = 0;
         
-        virtual void fileTransferProgress(MSN::FileTransferInvitation * inv, 
std::string status, unsigned long recv, unsigned long total) = 0;
+        virtual void fileTransferProgress(MSN::FileTransferInvitation * inv, 
const std::string & status, unsigned long recv, unsigned long total) = 0;
         
-        virtual void fileTransferFailed(MSN::FileTransferInvitation * inv, int 
error, std::string message) = 0;
+        virtual void fileTransferFailed(MSN::FileTransferInvitation * inv, int 
error, const std::string & message) = 0;
         
         virtual void fileTransferSucceeded(MSN::FileTransferInvitation * inv) 
= 0;
         

Deleted: trunk/msn/filetransfer.cpp
===================================================================
--- trunk/msn/filetransfer.cpp  2005-07-11 23:42:29 UTC (rev 358)
+++ trunk/msn/filetransfer.cpp  2005-07-12 03:08:54 UTC (rev 359)
@@ -1,528 +0,0 @@
-/*
- * filetransfer.cpp
- * libmsn
- *
- * Created by Mark Rowe on Wed Mar 17 2004.
- * Copyright (c) 2004 Mark Rowe. 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 <msn/filetransfer.h>
-#include <msn/message.h>
-#include <msn/errorcodes.h>
-#include <msn/externals.h>
-#include <msn/notificationserver.h>
-
-#ifndef WIN32
-#include <unistd.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#else
-#include <winsock.h>
-#include <io.h>
-#endif
-
-#include <cerrno>
-#include <cassert>
-
-namespace MSN 
-{
-    static const unsigned int MAX_FTP_BLOCK_SIZE = 20000;
-    
-    void FileTransferInvitation::invitationWasAccepted(const std::string & 
body)
-    {
-        if (this->invitationWasSent())
-        {
-            this->sendFile(body);
-        }
-        else
-        {
-            this->receiveFile(body);
-        }
-    }
-    
-    void FileTransferInvitation::invitationWasCanceled(const std::string & 
body)
-    {
-        
this->switchboardConnection->myNotificationServer()->externalCallbacks.fileTransferFailed(this,
 0, "Cancelled by remote user");
-        if (this->invitationWasSent())
-        {
-            this->switchboardConnection->invitationsSent.remove(this);
-        }
-        else 
-        {
-            this->switchboardConnection->invitationsReceived.remove(this);
-        }
-        this->switchboardConnection->removeFileTransferConnection(this);
-    }
-    
-    void FileTransferInvitation::sendFile(const std::string & msg_body)
-    {
-        int port = 6891;
-        char tmp[64];
-        sprintf(tmp, "%d", rand());
-        FileTransferConnection * conn = new 
FileTransferConnection(this->switchboardConnection->auth.username, 
-                                                                   
std::string(tmp), FileTransferConnection::MSNFTP_SEND, this);
-        
-        
this->switchboardConnection->myNotificationServer()->externalCallbacks.fileTransferProgress(this,
 "Sending IP address", 0, 0);
-        
-        while((conn->sock = 
this->switchboardConnection->myNotificationServer()->externalCallbacks.listenOnPort(port))
 < 0)
-        {
-            port++;
-            if (port > 6911)
-            {
-                
this->switchboardConnection->myNotificationServer()->externalCallbacks.fileTransferFailed(this,
 errno, strerror(errno));
-                this->switchboardConnection->invitationsSent.remove(this);
-                conn->disconnect();
-                return;
-            }
-        }
-        
-        
this->switchboardConnection->myNotificationServer()->externalCallbacks.registerSocket(conn->sock,
 1, 0);
-        
-        this->switchboardConnection->addFileTransferConnection(conn);
-        
-        std::ostringstream buf_;
-        buf_ << "Invitation-Command: ACCEPT\r\n";
-        buf_ << "Invitation-Cookie: " << this->cookie << "\r\n";
-        buf_ << "IP-Address: " << 
this->switchboardConnection->myNotificationServer()->externalCallbacks.getOurIP()
 << "\r\n";
-        buf_ << "Port: " << port << "\r\n";
-        buf_ << "AuthCookie: " << conn->auth.cookie << "\r\n";
-        buf_ << "Launch-Application: FALSE\r\n";
-        buf_ << "Request-Data: IP-Address:\r\n";
-        buf_ << "\r\n";
-        
-        Message * msg = new Message(buf_.str());
-        msg->setHeader("Content-Type", "text/x-msmsgsinvite; charset=UTF-8");
-        this->switchboardConnection->sendMessage(msg);
-        delete msg;
-    }
-    
-    void FileTransferInvitation::receiveFile(const std::string & msg_body)
-    {
-        Message::Headers headers(msg_body);
-        std::string cookie = headers["AuthCookie"];
-        std::string remote = headers["IP-Address"];
-        std::string port_c = headers["Port"];
-        int port;
-        
-        if (cookie.empty() || remote.empty() || port_c.empty())
-        {
-            
this->switchboardConnection->myNotificationServer()->externalCallbacks.fileTransferFailed(this,
 0, "Missing parameters");
-            this->switchboardConnection->invitationsReceived.remove(this);
-            return;
-        }
-        
-        port = decimalFromString(port_c);
-        FileTransferConnection * conn = new 
FileTransferConnection(this->switchboardConnection->auth.username,
-                                                                   cookie, 
FileTransferConnection::MSNFTP_RECV, this);
-        
-        std::ostringstream buf_;
-        buf_ << "Connecting to " << remote << ":" << port << "\n";
-        
this->switchboardConnection->myNotificationServer()->externalCallbacks.fileTransferProgress(this,
 buf_.str(), 0, 0);
-        
-        conn->sock = 
this->switchboardConnection->myNotificationServer()->externalCallbacks.connectToServer(remote,
 port, &conn->connected);
-        
-        if (conn->sock < 0)
-        {
-            
this->switchboardConnection->myNotificationServer()->externalCallbacks.fileTransferFailed(this,
 errno, strerror(errno));
-            this->switchboardConnection->invitationsReceived.remove(this);
-            return;
-        }
-
-        if (! conn->isConnected())
-            
this->switchboardConnection->myNotificationServer()->externalCallbacks.registerSocket(conn->sock,
 0, 1);
-        else
-            
this->switchboardConnection->myNotificationServer()->externalCallbacks.registerSocket(conn->sock,
 1, 0);
-        
-        
this->switchboardConnection->myNotificationServer()->externalCallbacks.fileTransferProgress(this,
 "Connected", 0, 0);
-        this->switchboardConnection->addFileTransferConnection(conn);
-        
-        conn->write("VER MSNFTP\r\n");
-    }
-    
-    void FileTransferConnection::disconnect()
-    {
-        Connection::disconnect();
-        
-        if (this->auth.fd)
-        {
-            fclose(this->auth.fd);
-            this->auth.fd = NULL;
-        }
-        
-        
this->auth.inv->switchboardConnection->removeFileTransferConnection(this);
-        delete this->auth.inv;
-        this->auth.inv = NULL;
-    }
-    
-    FileTransferConnection::~FileTransferConnection()
-    {
-        this->disconnect();
-    }
-    
-    void FileTransferConnection::socketConnectionCompleted()
-    {
-        Connection::socketConnectionCompleted();
-        
this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock);
-        
this->myNotificationServer()->externalCallbacks.registerSocket(this->sock, 1, 
0);
-    }    
-    
-    void FileTransferConnection::socketIsWritable()
-    {
-        if (this->auth.direction == MSNFTP_SEND)
-            this->handleSend();
-    }
-    
-    void FileTransferConnection::dataArrivedOnSocket()
-    {
-        if (this->auth.direction == MSNFTP_SEND && ! this->auth.connected)
-            this->handleSend();
-        else
-            Connection::dataArrivedOnSocket();
-    }
-    
-    void FileTransferConnection::handleIncomingData()
-    {
-        if (this->auth.direction == MSNFTP_RECV)
-            this->handleReceive();
-        else 
-            this->handleSend();
-    }
-    
-    void FileTransferConnection::handleSend()
-    {
-        if (! this->auth.connected) // we have not accept()ed yet, but the 
read/writability means there's one waiting
-        {
-            this->handleSend_WaitingForConnection();
-        } 
-        else if (this->auth.fd == NULL)
-        {
-            this->handleSend_Negotiating();
-        }
-        else if (this->auth.inv->fileSize != this->auth.bytes_done)
-        {
-            this->handleSend_Transferring();
-        }
-        else
-        {
-            this->handleSend_Bye();
-        }
-    }
-    
-    void FileTransferConnection::handleSend_WaitingForConnection()
-    {
-        int s;
-        
-        if ((s = accept(this->sock, NULL, NULL)) < 0)
-        {
-            perror("Could not accept()\n");
-            
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
-            
this->auth.inv->switchboardConnection->invitationsSent.remove(this->auth.inv);
-            return;
-        }
-        
-        
this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock);
-        close(this->sock);
-        
-        this->sock = s;
-        
this->myNotificationServer()->externalCallbacks.registerSocket(this->sock, 1, 
0);
-        
-        
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Connected", 0, 0);
-        
-        this->auth.connected = 1;
-        this->connected = true;        
-    }
-    
-    void FileTransferConnection::handleSend_Negotiating()
-    {
-        if (! this->isWholeLineAvailable())
-            return;
-        
-        std::vector<std::string> args = this->getLine();
-        this->readBuffer = 
this->readBuffer.substr(this->readBuffer.find("\r\n") + 2);
-                
-        if (args[0] == "VER")
-        {
-            if (this->write("VER MSNFTP\r\n") != strlen("VER MSNFTP\r\n"))
-                return;
-            
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Negotiating", 0, 0);
-        }
-        else if (args[0] == "USR")
-        {
-            if (args[2] != this->auth.cookie)  // if they DIFFER
-            {
-                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
-                
this->auth.inv->switchboardConnection->invitationsSent.remove(this->auth.inv);
-                return;
-            }
-            std::ostringstream buf_;
-            buf_ << "FIL " << this->auth.inv->fileSize << "\r\n";
-            this->write(buf_);
-        }
-        else if (args[0] == "TFR")
-        {
-            // you asked for it, go to data-dump mode
-            this->auth.fd = fopen(this->auth.inv->fileName.c_str(), "r");
-            if (this->auth.fd == NULL)
-            {
-                perror("fopen() failed");
-                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, "Could not open file for reading");
-                
this->auth.inv->switchboardConnection->invitationsSent.remove(this->auth.inv);
-                return;
-            }
-            
-            // OK, now we lose control, but the next round of the polling loop 
will
-            // say that the socket is writable, and then the fun starts...
-            
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Sending data", 0, 0);
-            
this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock);
-            
this->myNotificationServer()->externalCallbacks.registerSocket(this->sock, 0, 
1);                        
-        }
-    }
-    
-    void FileTransferConnection::handleSend_Transferring()
-    {
-        // just pumping data now
-        
-        fd_set writefd;
-        FD_ZERO(&writefd);
-        FD_SET(this->sock, &writefd);
-        struct timeval tout={0, 0};
-        unsigned char *readBuffer = (unsigned char *) 
calloc(MAX_FTP_BLOCK_SIZE, sizeof(unsigned char));
-        
-        if (select(this->sock + 1, NULL, &writefd, NULL, &tout) == 1)
-        {
-            int bytesWritten = 0;
-            unsigned int blockLength;
-            unsigned char blockHeader[3];
-            unsigned int bytesRemaining = this->auth.inv->fileSize - 
this->auth.bytes_done;
-            blockLength = bytesRemaining > MAX_FTP_BLOCK_SIZE / 4 ? 
MAX_FTP_BLOCK_SIZE / 4 : bytesRemaining;
-            if (blockLength == 0)
-                blockHeader[0] = 1;
-            else
-                blockHeader[0] = 0;
-            blockHeader[1] = (blockLength >> 0) & 0xff;
-            blockHeader[2] = (blockLength >> 8) & 0xff;
-            
-            if (this->write(std::string((char *) &blockHeader[bytesWritten], 3 
- bytesWritten), false) != 3)
-            {
-                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
-                goto cleanup;
-            }
-            
-            if (fread(readBuffer, sizeof(unsigned char), blockLength, 
this->auth.fd) < 0)
-            {
-                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
-                goto cleanup;
-            }
-            
-            if ((blockLength = this->write(std::string((char *) readBuffer, 
blockLength), false)) < 0)
-            {
-                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
-                goto cleanup;
-            }
-            this->auth.bytes_done += blockLength;
-        }
-        free(readBuffer);
-        
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Sending file", this->auth.bytes_done, this->auth.inv->fileSize);
-        return;
-cleanup:
-            ;
-        
this->auth.inv->switchboardConnection->invitationsSent.remove(this->auth.inv);
-        if (readBuffer)
-            free(readBuffer);
-        if (this->auth.fd)
-        {
-            fclose(this->auth.fd);
-            this->auth.fd = NULL;
-        }
-    }
-    
-    void FileTransferConnection::handleSend_Bye()
-    {
-        
this->myNotificationServer()->externalCallbacks.fileTransferSucceeded(this->auth.inv);
-        
-        
this->auth.inv->switchboardConnection->invitationsSent.remove(this->auth.inv);
-        this->disconnect();
-    }
-    
-    
-    void FileTransferConnection::handleReceive()
-    {
-        if (this->auth.fd == NULL)
-            this->handleReceive_Negotiating();
-        else
-            this->handleReceive_Transferring();
-    }
-    
-    void FileTransferConnection::handleReceive_Negotiating()
-    {
-        if (! this->isWholeLineAvailable())
-            return;
-                
-        std::vector<std::string> args = this->getLine();
-        this->readBuffer = 
this->readBuffer.substr(this->readBuffer.find("\r\n") + 2);        
-        
-        if (args[0] == "VER")
-        {
-            std::ostringstream buf_;
-            buf_ << "USR " << this->auth.username << " " << this->auth.cookie 
<< "\r\n";
-            this->write(buf_);
-            
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Negotiating", 0, 0);
-            return;
-        } 
-        else if (args[0] == "FIL")
-        {
-            this->auth.fd = fopen(this->auth.inv->fileName.c_str(), "w");
-            if (this->auth.fd == NULL)
-                goto error;
-            
-            this->write("TFR\r\n");
-        }
-        return;
-error:
-            ;
-        
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
-        
this->switchboardConnection()->invitationsReceived.remove(this->auth.inv);
-    }
-    
-    void FileTransferConnection::handleReceive_Transferring()
-    {
-        // Each block has a 3-byte header
-        // 0: either 1 or 0.  0 means data block, 1 means transfer completed.
-        // 1: Low byte of block length
-        // 2: High byte of block length
-        
-        unsigned int blockLength;
-        std::string blockHeader;
-        
-        while (1)
-        {
-            if (this->readBuffer.size() < 3)
-                return;
-            
-            // read the three byte header
-            blockHeader = this->readBuffer.substr(0, 3);
-            if (blockHeader[0] == 1U)
-            {
-                // Transfer completed block
-                if (blockHeader[1] != 0 || blockHeader[2] != 0)
-                {
-                    
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 0, "Invalid block header.\n");
-                    goto cleanup;
-                }
-                this->write("BYE 16777989\r\n");
-                
this->myNotificationServer()->externalCallbacks.fileTransferSucceeded(this->auth.inv);
-                
-                goto cleanup;
-            }
-            else if (blockHeader[0] != 0U)
-            {
-                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 0, "Invalid block header.");
-                goto cleanup;
-            }
-            
-            // Read the entire block
-            blockLength = ((unsigned char) blockHeader[1]) | ((unsigned char) 
blockHeader[2]) << 8;
-            if (blockLength > MAX_FTP_BLOCK_SIZE)
-            {
-                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 0, "Block size greater than largest expected block size.");
-                goto cleanup;
-            }
-            
-            if (this->readBuffer.size() < 3 + blockLength)
-                return;
-            
-            std::string block = this->readBuffer.substr(3, blockLength);
-            this->readBuffer = this->readBuffer.substr(3 + blockLength);
-            
-            fwrite(block.c_str(), sizeof(unsigned char), block.size(), 
this->auth.fd);
-            this->auth.bytes_done += blockLength;
-            
-            if (this->auth.bytes_done == this->auth.inv->fileSize)
-            {
-                // It appears that sometimes the 1,0,0 block header
-                // that indicates success isnt sent...
-                
-                this->write("BYE 16777989\r\n");
-                
this->myNotificationServer()->externalCallbacks.fileTransferSucceeded(this->auth.inv);
-                goto cleanup;
-            }
-            
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Receiving file", this->auth.bytes_done, this->auth.inv->fileSize);
-        }
-        return;
-cleanup:
-            ;
-        
this->auth.inv->switchboardConnection->invitationsReceived.remove(this->auth.inv);
-        if (this->auth.fd)
-        {
-            fclose(this->auth.fd);
-            this->auth.fd = NULL;
-        }
-    }
-    
-    void FileTransferInvitation::rejectTransfer()
-    {
-        std::ostringstream buf_;
-        buf_ << "Invitation-Command: CANCEL\r\n";
-        buf_ << "Invitation-Cookie: " << this->cookie << "\r\n";
-        buf_ << "Cancel-Code: REJECT\r\n";
-        
-        Message *msg = new Message(buf_.str());
-        msg->setHeader("Content-Type", "text/x-msmsgsinvite; charset=UTF-8");
-        this->switchboardConnection->sendMessage(msg);
-        delete msg;
-        
-        this->switchboardConnection->invitationsReceived.remove(this);
-    }
-    
-    void FileTransferInvitation::acceptTransfer(const std::string & dest)
-    {
-        std::ostringstream buf_;
-        buf_ << "Invitation-Command: ACCEPT\r\n";
-        buf_ << "Invitation-Cookie: " << (this->cookie.empty() ? "" : 
this->cookie) << "\r\n";
-        buf_ << "Launch-Application: FALSE\r\n";
-        buf_ << "Request-Data: IP-Address\r\n";
-        buf_ << "\r\n";
-        
-        this->fileName = dest;
-        Message *msg = new Message(buf_.str());
-        msg->setHeader("Content-Type", "text/x-msmsgsinvite; charset=UTF-8");
-        this->switchboardConnection->sendMessage(msg);
-        delete msg;
-        
-    }
-    
-    void FileTransferInvitation::cancelTransfer()
-    {
-        std::ostringstream buf_;
-        buf_ << "Invitation-Command: CANCEL\r\n";
-        buf_ << "Invitation-Cookie: " << this->cookie << "\r\n";
-        buf_ << "Cancel-Code: OUTBANDCANCEL\r\n";
-        
-        Message *msg = new Message(buf_.str());
-        msg->setHeader("Content-Type", "text/x-msmsgsinvite; charset=UTF-8");
-        this->switchboardConnection->sendMessage(msg);
-        delete msg;    
-        
-        // one of the two below will fail, but it will do so safely and quietly
-        this->switchboardConnection->invitationsReceived.remove(this);
-        this->switchboardConnection->invitationsSent.remove(this);
-        
-        this->switchboardConnection->removeFileTransferConnection(this);
-    }
-}

Deleted: trunk/msn/filetransfer.h
===================================================================
--- trunk/msn/filetransfer.h    2005-07-11 23:42:29 UTC (rev 358)
+++ trunk/msn/filetransfer.h    2005-07-12 03:08:54 UTC (rev 359)
@@ -1,235 +0,0 @@
-#ifndef __msn_filetransfer_h__
-#define __msn_filetransfer_h__
-
-/*
- * filetransfer.h
- * libmsn
- *
- * Created by Mark Rowe on Wed Mar 17 2004.
- * Copyright (c) 2004 Mark Rowe. 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 <msn/util.h>
-#include <msn/switchboardserver.h>
-#include <msn/invitation.h>
-#include <msn/passport.h>
-
-#include <string>
-#include <stdio.h>
-
-namespace MSN 
-{
-    /** Contains information about the invitation that was sent or received 
when
-     *  a file transfer was initiated.
-     */
-    class FileTransferInvitation : public Invitation
-    {
-public:
-        /** The name of the file that is being transferred.
-         */
-        std::string fileName;
-        
-        /** The size in bytes of the file that is being transferred.
-         */
-        long unsigned fileSize;
-        
-        /** A pointer to user-specified data that can be used to identify this
-         *  transfer.
-         */
-        void * userData;
-        
-        /** Create a new FileTransferInvitation.
-         *
-         *  @todo  Do all of these parameters really need to be in the 
constructor?
-         */
-        FileTransferInvitation(Invitation::ApplicationType application_, 
std::string cookie_,
-                       Passport otherUser_, SwitchboardServerConnection * 
switchboardConnection_,
-                       std::string fileName_, long unsigned fileSize_, void 
*userData_ = NULL) :
-            Invitation(application_, cookie_, otherUser_, 
switchboardConnection_),
-            fileName(fileName_), fileSize(fileSize_), userData(userData_) {};
-
-        FileTransferInvitation(const FileTransferInvitation & invitation_) : 
-            Invitation(invitation_), fileName(invitation_.fileName), 
fileSize(invitation_.fileSize), userData(invitation_.userData) {};
-        
-        FileTransferInvitation &operator=(const FileTransferInvitation & 
invitation_)
-        {
-            Invitation::operator=(invitation_);
-            fileName = invitation_.fileName;
-            fileSize = invitation_.fileSize;
-            userData = invitation_.userData;
-            return *this;
-        }
-
-        /** The remote side accepted our file transfer.  Notify calling code.
-         */
-        virtual void invitationWasAccepted(const std::string & body);
-        
-        /** The remote side canceled our file transfer.  Notify calling code.
-         */
-        virtual void invitationWasCanceled(const std::string & body);
-        
-        /** The user wishes to accept the file transfer, and have the file
-         *  written to @a destinationFile.
-         *
-         *  @todo Should the received data be passed back to the user to store
-         *        in the file?  This would remove some of the complexity in the
-         *        file transfer code.
-         */
-        void acceptTransfer(const std::string & destinationFile);
-        
-        /** The user wishes to decline the file transfer.
-         */
-        void rejectTransfer();
-        
-        /** The user wishes to cancel the file transfer.
-         */
-        void cancelTransfer();
-private:        
-        void sendFile(const std::string & msg_body);
-        void receiveFile(const std::string & msg_body);
-    };    
-    
-    
-    /** Represents a connection to another users computer for the purpose of
-     *  transferring a file.
-     *
-     *  @todo Finish refactoring to store progress explicitly rather than in
-     *        a complex combination of member variables.
-     */
-    class FileTransferConnection : public Connection
-    {
-public:
-        
-        /** Are we sending or receiving the file?
-         */
-        typedef enum 
-        {
-            MSNFTP_SEND,
-            MSNFTP_RECV
-        } Direction;
-        
-        /** Are we being connected to or connecting to them?
-         */
-        typedef enum
-        {
-            MSNFTP_SERVER,
-            MSNFTP_CLIENT
-        } Perspective;
-        
-        /** How far through the process are we?
-         */
-        typedef enum
-        {
-            WAITING_FOR_CONNECTION,
-            NEGOTIATING,
-            TRANSFERRING
-        } Progress;
-        
-        /** AuthData contains authentication information
-         *  relating to a FileTransferConnection.
-         */
-        class AuthData : public ::MSN::AuthData
-        {
-public:
-            /** A string that uniquely identifies this transfer.
-             *  
-             * It is generated during the negotiation of the transfer over the 
SwitchboardServerConnection
-             */
-            std::string cookie;
-            
-            /** Which direction is the file being sent? */
-            Direction direction;
-            
-            /** Should we serve or connect? */
-            Perspective perspective;
-            
-            /** The invitiation that we are associated with. */
-            FileTransferInvitation *inv;
-            
-            /** The file descriptor that data will be read from or written to 
*/
-            FILE *fd;
-            
-            /** Is the transfer connected? */
-            bool connected;
-            
-            /** How many bytes have we transferred? */
-            unsigned long bytes_done;
-            
-            /** Initialize an AuthData instance with the given parameters. */
-            AuthData(Passport username_, std::string cookie_, Direction 
direction_, 
-                                 FileTransferInvitation *inv_=NULL, FILE 
*fd_=NULL, bool connected_=false,
-                                 unsigned long bytes_done_=0) :
-                ::MSN::AuthData(username_), cookie(cookie_), 
direction(direction_),
-                perspective((direction == MSNFTP_RECV ? MSNFTP_CLIENT : 
MSNFTP_SERVER)), inv(inv_), 
-                fd(fd_), connected(connected_), bytes_done(bytes_done_) {};
-            AuthData(const AuthData & auth_) : 
-                ::MSN::AuthData(auth_), cookie(auth_.cookie), 
direction(auth_.direction),
-                perspective(auth_.perspective), inv(auth_.inv),
-                fd(auth_.fd), connected(auth_.connected), 
bytes_done(auth_.bytes_done) {};
-            virtual ~AuthData() { if (fd) fclose(fd); };
-            
-            AuthData &operator=(const AuthData & auth_)
-            {
-                ::MSN::AuthData::operator=(auth_);
-                cookie = auth_.cookie;
-                direction = auth_.direction;
-                perspective = auth_.perspective;
-                inv = auth_.inv;
-                fd = auth_.fd;
-                connected = auth_.connected;
-                bytes_done = auth_.bytes_done;
-                return *this;
-            }
-        };
-        
-        /** The AuthData relating to this connection */
-        FileTransferConnection::AuthData auth;
-        
-        /** Initialize this connection with an existing AuthData instance. */
-        FileTransferConnection(Passport username_, std::string cookie_, 
Direction direction_, 
-                               FileTransferInvitation *inv_=NULL, FILE 
*fd_=NULL, bool connected_=false,
-                               unsigned long bytes_done_=0) :
-            Connection(),
-            auth(username_, cookie_, direction_, inv_, fd_, connected_, 
bytes_done_) {};
-        virtual ~FileTransferConnection();
-        
-        /** @todo Should this really be an empty function? */
-        virtual void connect(const std::string & hostname, unsigned int port) 
{};
-        virtual void disconnect();
-
-        virtual void socketIsWritable();
-        virtual void socketConnectionCompleted();
-        virtual void dataArrivedOnSocket();
-        virtual NotificationServerConnection *myNotificationServer() { return 
switchboardConnection()->myNotificationServer(); };        
-private:
-        virtual void handleIncomingData();
-        virtual void dispatchCommand(std::vector<std::string> & args) {};
-        void handleSend();
-        void handleReceive();
-        
-        void handleSend_WaitingForConnection();
-        void handleSend_Negotiating();
-        void handleSend_Transferring();
-        void handleSend_Bye();
-        
-        void handleReceive_Negotiating();
-        void handleReceive_Transferring();
-        
-        SwitchboardServerConnection *switchboardConnection() { return 
this->auth.inv->switchboardConnection; };
-    };
-}
-#endif

Copied: trunk/msn/impl/authdata.h (from rev 356, trunk/msn/authdata.h)
===================================================================
--- trunk/msn/authdata.h        2005-07-11 23:24:29 UTC (rev 356)
+++ trunk/msn/impl/authdata.h   2005-07-12 03:08:54 UTC (rev 359)
@@ -0,0 +1,40 @@
+/*
+ * authdata.h
+ * libmsn
+ *
+ * Created by Mark Rowe on Mon Mar 22 2004.
+ * Copyright (c) 2004 Mark Rowe. 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 <string>
+#include <msn/passport.h>
+#include <msn/uncopyable.h>
+
+namespace MSN
+{
+    class AuthData : private Uncopyable
+    {
+public:
+        Passport username;
+        
+        AuthData(const Passport & username_) : username(username_) {};
+        AuthData(const AuthData & auth_) : username(auth_.username) {};
+        virtual ~AuthData() {};
+        
+        AuthData &operator=(const AuthData & auth_) { username = 
auth_.username; return *this; };
+    };
+}

Copied: trunk/msn/impl/buddy.cpp (from rev 356, trunk/msn/buddy.cpp)
===================================================================
--- trunk/msn/buddy.cpp 2005-07-11 23:24:29 UTC (rev 356)
+++ trunk/msn/impl/buddy.cpp    2005-07-12 03:08:54 UTC (rev 359)
@@ -0,0 +1,75 @@
+/*
+ * buddy.cpp
+ * libmsn
+ *
+ * Created by Mark Rowe on Mon Apr 19 2004.
+ * Copyright (c) 2004 Mark Rowe. 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 <msn/buddy.h>
+#include "buddy.h"
+#include <cassert>
+
+namespace MSN
+{
+    std::string buddyStatusToString(BuddyStatus state)
+    {
+        switch (state)
+        {
+            case STATUS_AVAILABLE:
+                return "NLN";
+            case STATUS_BUSY:
+                return "BSY";
+            case STATUS_IDLE:
+                return "IDL";
+            case STATUS_BERIGHTBACK:
+                return "BRB";
+            case STATUS_AWAY:
+                return "AWY";
+            case STATUS_ONTHEPHONE:
+                return "PHN";
+            case STATUS_OUTTOLUNCH:
+            return "LUN";
+            case STATUS_INVISIBLE:
+                return "HDN";
+            default:
+                assert(false);
+        }
+    }
+    
+    BuddyStatus buddyStatusFromString(std::string state)
+    {
+        if (state == "NLN")
+            return STATUS_AVAILABLE;
+        else if (state == "BSY")
+            return STATUS_BUSY;
+        else if (state == "IDL")
+            return STATUS_IDLE;
+        else if (state == "BRB")
+            return STATUS_BERIGHTBACK;
+        else if (state == "AWY")
+            return STATUS_AWAY;
+        else if (state == "PHN")
+            return STATUS_ONTHEPHONE;
+        else if (state == "LUN")
+            return STATUS_OUTTOLUNCH;
+        else if (state == "HDN")
+            return STATUS_INVISIBLE;
+        else
+            throw std::runtime_error("Unknown status!");
+    }
+}

Copied: trunk/msn/impl/buddy.h (from rev 356, trunk/msn/buddy.h)
===================================================================
--- trunk/msn/buddy.h   2005-07-11 23:24:29 UTC (rev 356)
+++ trunk/msn/impl/buddy.h      2005-07-12 03:08:54 UTC (rev 359)
@@ -0,0 +1,114 @@
+/*
+ * buddy.h
+ * libmsn
+ *
+ * Created by Mark Rowe on Mon Apr 19 2004.
+ * Copyright (c) 2004 Mark Rowe. 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 <string>
+#include <list>
+#include <msn/buddy.h>
+#include <msn/uncopyable.h>
+#include <msn/passport.h>
+
+namespace MSN
+{
+    class Group;
+    
+    /** The Buddy class contains information about a member of a buddy list.
+     *
+     *  Each Buddy is made up of their passport address (@a userName),
+     *  user-visible display name (@a friendlyName), zero or more @a 
phoneNumbers,
+     *  and zero or more @a groups on the buddy list that they belong to.
+     *
+     *  It is only currently used during MSN::Callbacks::gotBuddyListInfo to
+     *  store contact information about a buddy that was retrieved during
+     *  the buddy list synchronisation process.
+     */
+    class BuddyImpl : private Uncopyable
+    {
+        /** @todo  BPR's need to be handled at any time, not just when 
syncing. */
+public:        
+        /** Their passport address */
+        Passport userName;
+        
+        /** Their friendly name */
+        std::string friendlyName;
+        
+        /** A list of phone numbers related to this buddy */
+        std::list<Buddy::PhoneNumber> phoneNumbers;
+        
+        /** A list of Group's that this buddy is a member of */
+        std::list<Group *> groups;
+        
+        /** Initialize the Buddy with the given @a userName_ and @a 
friendlyName_ */
+        BuddyImpl(Passport userName_, std::string friendlyName_) :
+            userName(userName_), friendlyName(friendlyName_),
+            phoneNumbers(), groups() {};
+    };
+    
+    /** The Group class represents a group of contacts on the buddy list.
+     *
+     *  Each group is represented by an integer @a groupID and has a 
user-visible
+     *  @a name.
+     */
+    class GroupImpl : private Uncopyable
+    {
+public:
+        /** The group ID */
+        int groupID;
+        
+        /** The group name */
+        std::string name;
+        
+        /** A list of buddies in the group */
+        std::list<Buddy *> buddies;
+        
+        /** Initialize a Group with the given @a groupID_ and @a name_ */
+        GroupImpl(int groupID_, std::string name_)
+            : groupID(groupID_), name(name_), buddies() {};
+        
+        /** Initialize an empty, invalid group. */
+        GroupImpl() : groupID(-1), name("INVALID"), buddies() {};
+    };
+
+
+    /** The PhoneNumber class contains information about a single phone number
+     *  that is retrieved during the buddy list synchronisation process.
+     */
+    class PhoneNumberImpl : private Uncopyable
+    {
+public:
+        /** The name of this phone number.
+        *
+        *  @todo Should this be an enumeration containing the possible
+        *        types of phone number?
+        */
+        std::string title;
+        
+        /** The phone number */
+        std::string number;
+        
+        /** @todo Document me! */
+        bool enabled;
+        
+        /** Initialize a PhoneNumber with the given @a title_ and phone @a 
number_ */
+        PhoneNumberImpl(std::string title_, std::string number_, bool 
enabled_=true)
+            : title(title_), number(number_), enabled(enabled_) {};
+    };
+}

Copied: trunk/msn/impl/connection.cpp (from rev 356, trunk/msn/connection.cpp)
===================================================================
--- trunk/msn/connection.cpp    2005-07-11 23:24:29 UTC (rev 356)
+++ trunk/msn/impl/connection.cpp       2005-07-12 03:08:54 UTC (rev 359)
@@ -0,0 +1,314 @@
+/*
+ * connection.cpp
+ * libmsn
+ *
+ * Created by Mark Rowe on Mon Mar 22 2004.
+ * Copyright (c) 2004 Mark Rowe. 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 "connection.h"
+#include <msn/errorcodes.h>
+#include <msn/util.h>
+#include <msn/passport.h>
+#include <msn/externals.h>
+#include <msn/notificationserver.h>
+#include <msn/message.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#else
+#include <winsock.h>
+#include <io.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <cerrno>
+#include <time.h>
+#include <cassert>
+
+namespace MSN
+{
+    std::map<std::string, void (ConnectionImpl::*)(std::vector<std::string> &, 
std::string, std::string)> ConnectionImpl::messageHandlers;
+    static std::vector<std::string> errors;
+
+    ConnectionImpl::ConnectionImpl() 
+        : sock(0), connected(false), trID(1), readBuffer(), writeBuffer()
+    {
+        srand((unsigned int) time(NULL));
+
+        if (errors.size() != 0)
+        {
+            assert(errors.size() == 1000);
+        }
+        else
+        {
+            errors.resize(1000);
+            for (int a = 0; a < 1000; a++)
+            {
+                errors[a] = "Unknown error code";
+            }
+            
+            errors[200] = "Syntax error";
+            errors[201] = "Invalid parameter";
+            errors[205] = "Invalid user";
+            errors[206] = "Domain name missing from username";
+            errors[207] = "Already logged in";
+            errors[208] = "Invalid username";
+            errors[209] = "Invalid friendly name";
+            errors[210] = "List full";
+            errors[215] = "This user is already on this list or in this 
session";
+            errors[216] = "Not on list";
+            errors[218] = "Already in this mode";
+            errors[219] = "This user is already in the opposite list";
+            errors[280] = "Switchboard server failed";
+            errors[281] = "Transfer notification failed";
+            errors[300] = "Required fields missing";
+            errors[302] = "Not logged in";
+            errors[500] = "Internal server error";
+            errors[501] = "Database server error";
+            errors[510] = "File operation failed at server";
+            errors[520] = "Memory allocation failed on server";
+            errors[600] = "The server is too busy";
+            errors[601] = "The server is unavailable";
+            errors[602] = "A Peer Notification Server is down";
+            errors[603] = "Database connection failed";
+            errors[604] = "Server going down for maintenance";
+            errors[707] = "Server failed to create connection";
+            errors[711] = "Blocking write failed on server";
+            errors[712] = "Session overload on server";
+            errors[713] = "You have been too active recently. Slow down!";
+            errors[714] = "Too many sessions open";
+            errors[715] = "Not expected";
+            errors[717] = "Bad friend file on server";
+            errors[911] = "Authentication failed. Check that you typed your 
username and password correctly.";
+            errors[913] = "This action is not allowed while you are offline";
+            errors[920] = "This server is not accepting new users";            
+        }
+
+        if (messageHandlers.size() == 0)
+        {
+            messageHandlers["text/plain"]                            = 
&ConnectionImpl::message_plain;
+            messageHandlers["text/x-msmsgsinitialemailnotification"] = 
&ConnectionImpl::message_initial_email_notification;
+            messageHandlers["text/x-msmsgsemailnotification"]        = 
&ConnectionImpl::message_email_notification;
+            messageHandlers["text/x-msmsgsinvite"]                   = 
&ConnectionImpl::message_invitation;
+            messageHandlers["text/x-msmsgscontrol"]                  = 
&ConnectionImpl::message_typing_user;            
+        }
+    }
+    
+    ConnectionImpl::~ConnectionImpl() {}
+    
+    void ConnectionImpl::disconnect()
+    {
+//        
this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock);
+        ::close(this->sock);
+        this->sock = -1;
+        this->writeBuffer.erase();
+        this->readBuffer.erase();
+        this->trID = 1;
+    }
+    
+    std::vector<std::string> ConnectionImpl::getLine()
+    {
+        assert(this->isWholeLineAvailable());
+        std::string s = this->readBuffer.substr(0, 
this->readBuffer.find("\r\n"));
+//        this->myNotificationServer()->externalCallbacks.log(0, (s + 
"\n").c_str());
+        return splitString(s, " ");
+    }
+    
+    bool ConnectionImpl::isWholeLineAvailable()
+    {
+        return this->readBuffer.find("\r\n") != std::string::npos;
+    }
+    
+    void ConnectionImpl::errorOnSocket(int errno_)
+    {
+//        this->myNotificationServer()->externalCallbacks.showError(this, 
strerror(errno_));
+        this->disconnect();
+    }
+    
+    void ConnectionImpl::socketConnectionCompleted()
+    {
+        this->connected = true;
+        
+        // We know that we are connected, so this will try writing to the 
network.
+        size_t writtenLength = this->write(this->writeBuffer, 1);
+        this->writeBuffer = this->writeBuffer.substr(writtenLength);
+    }
+        
+    size_t ConnectionImpl::write(std::string s, bool log) throw 
(std::runtime_error)
+    {
+        if (! this->connected)
+            this->writeBuffer.append(s);
+        else
+        {
+//            if (log)
+//                this->myNotificationServer()->externalCallbacks.log(1, 
s.c_str());
+            
+            size_t written = 0;
+            while (written < s.size())
+            {
+                size_t newWritten = ::send(this->sock, 
s.substr(written).c_str(), (int) (s.size() - written), 0);
+                if (newWritten <= 0)
+                {
+                    if (errno == EAGAIN)
+                        continue;
+                    else
+                        break;
+                }
+                written += newWritten;
+            }
+            if (written != s.size())
+            {
+                this->errorOnSocket(errno);
+                return written;
+            }
+        }
+        return s.size();
+    }
+    
+    size_t ConnectionImpl::write(std::ostringstream & ss, bool log) throw 
(std::runtime_error)
+    {
+        std::string s = ss.str();
+        size_t result = write(s, log);
+        return result;        
+    }
+        
+    void ConnectionImpl::dataArrivedOnSocket()
+    {
+        char tempReadBuffer[8192];
+        int amountRead = ::recv(this->sock, &tempReadBuffer[0], 8192, 0);
+        if (amountRead < 0)
+        {
+            if (errno == EAGAIN)
+                return;
+            
+            // We shouldn't get EAGAIN here because dataArrivedOnSocket
+            // is only called when select/poll etc has told us that
+            // the socket is readable.
+            // assert(errno != EAGAIN);
+            
+//            this->myNotificationServer()->externalCallbacks.showError(this, 
strerror(errno));                
+            this->disconnect();            
+        }
+        else if (amountRead == 0)
+        {
+//            this->myNotificationServer()->externalCallbacks.showError(this, 
"Connection closed by remote endpoint.");
+            this->disconnect();
+        }
+        else
+        {
+            this->readBuffer += std::string(tempReadBuffer, amountRead);
+            try
+            {
+                handleIncomingData();
+            }
+            catch (std::exception & e)
+            {
+//                
this->myNotificationServer()->externalCallbacks.showError(this, e.what());
+            }
+        }
+    }
+    
+    void ConnectionImpl::handle_MSG(std::vector<std::string> & args)
+    {
+        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(mime);
+        contentType = headers["Content-Type"];
+        
+        if ((tmp = contentType.find("; charset")) != std::string::npos)
+            contentType = contentType.substr(0, tmp);
+        
+        std::map<std::string, void 
(ConnectionImpl::*)(std::vector<std::string> &, std::string, 
std::string)>::iterator i = messageHandlers.find(contentType);
+        if (i != messageHandlers.end())
+            (this->*(messageHandlers[contentType]))(args, mime, body);
+    }
+    
+    void ConnectionImpl::message_plain(std::vector<std::string> & args, 
std::string mime, std::string body)
+    {
+        Message msg(body, mime);
+        
+//        
this->myNotificationServer()->externalCallbacks.gotInstantMessage(static_cast<SwitchboardServerConnection
 *>(this),
+//                               args[1], decodeURL(args[2]), &msg);
+    }
+    
+    void 
ConnectionImpl::message_initial_email_notification(std::vector<std::string> & 
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(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 ConnectionImpl::message_email_notification(std::vector<std::string> & 
args, std::string mime, std::string body)
+    {
+        // New email notifications body is a set of MIME headers
+        Message::Headers headers(body);
+        
+        std::string from = headers["From-Addr"];
+        std::string subject = headers["Subject"];
+        
+//        
this->myNotificationServer()->externalCallbacks.gotNewEmailNotification(this, 
from, subject);
+    }
+
+    
+    void ConnectionImpl::message_invitation(std::vector<std::string> & args, 
std::string mime, std::string body)
+    {
+//        static_cast<SwitchboardServerConnection 
*>(this)->handleInvite(args[1], decodeURL(args[2]), mime, body);
+    }
+
+    void ConnectionImpl::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 ConnectionImpl::showError(int errorCode)
+    {
+        std::ostringstream buf_;
+        buf_ << "Error code: " << errorCode << " (" << errors[errorCode] << 
")";
+//        this->myNotificationServer()->externalCallbacks.showError(this, 
buf_.str());        
+    }
+}

Copied: trunk/msn/impl/connection.h (from rev 356, trunk/msn/connection.h)
===================================================================
--- trunk/msn/connection.h      2005-07-11 23:24:29 UTC (rev 356)
+++ trunk/msn/impl/connection.h 2005-07-12 03:08:54 UTC (rev 359)
@@ -0,0 +1,181 @@
+/*
+ * connection.h
+ * libmsn
+ *
+ * Created by Mark Rowe on Mon Mar 22 2004.
+ * Copyright (c) 2004 Mark Rowe. 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 <string>
+#include <list>
+#include <vector>
+#include <map>
+#include <msn/uncopyable.h>
+#include <msn/connection.h>
+#include "sstream_fix.h"
+#include <stdexcept>
+
+namespace MSN
+{
+    class callback;
+    class Message;
+    class Passport;
+    class NotificationServerConnection;
+    class SwitchboardServerConnection;
+    class FileTransferConnection;
+    class FileTransferInvitation;
+    
+    /** An abstract base class that represents a connection to another 
computer.
+     *
+     *  Connection provides an interface and some functionality that is common
+     *  to notification, switchboard and file transfer connections.
+     *
+     * @todo Connection should have a read buffer that stores all incoming data
+     *       that is waiting to be processed.  Member functions should use that
+     *       for necessary data, and <em>not</em> call Connection::readExactly.
+     */
+    class ConnectionImpl : private Uncopyable
+    {
+      friend class SwitchboardServerConnection;
+      friend class NotificationServerConnection;
+      friend class FileTransferConnection;
+      friend class FileTransferInvitation;
+      
+public:
+        /** The socket which connects this Connection to another computer
+         *
+         * @deprecated  In the future, this member will be made private.  Any
+         *              functions that access this member should be converted 
to
+         *              member functions of a subclass.
+         */
+        int sock;
+        
+        /** Indicates whether a connection has been established.
+         *
+         * @todo  This is currently public only because 
FileTransferInvitation::receiveFile
+         *        accesses it.  It should be made protected in the future, and
+         *        FileTransferInvitation refactored to remove it's dependency 
on
+         *        this attribute.
+         */
+        bool connected;
+        
+private:
+        /** The transaction ID of the next command to be sent.
+         */
+        int trID;
+        
+        std::string readBuffer;
+public: 
+        ConnectionImpl();
+        virtual ~ConnectionImpl();
+        
+        /** Connect ourself to @a hostname on @a port.
+         */
+        virtual void connect(const std::string & hostname, unsigned int port) 
= 0;
+        
+        /** Close the current connection.
+         *
+         * This should not be called if the connection is already disconnected.
+         */
+        virtual void disconnect() = 0;
+        
+        /** @name External Socket Hooks
+         *  
+         *  These members should be called whenever an appropriate socket event
+         *  occurs.
+         */
+        /** @{ */
+        
+        /** New data is available on the connection.
+         */
+        virtual void dataArrivedOnSocket();
+        
+        /** The connection has been established.
+         */
+        virtual void socketConnectionCompleted();
+        
+        /** The socket is ready for data to be written to it.
+         */
+        virtual void socketIsWritable() {};
+        
+        /** An error has occurred on the socket.
+         */
+        virtual void errorOnSocket(int errno_);
+        /** @} */
+                
+        /** Notify the calling library that an error with code @a errorCode has
+         *  occured.
+         */
+        void showError(int errorCode);
+        
+        /** Is this Connection connected to a remote endpoint?
+         */
+        bool isConnected() { return this->connected; };
+        
+        /** Retrieve the parent NotificationServerConnection from this 
connection */
+        virtual NotificationServerConnection *myNotificationServer() = 0;
+private:
+         /** Process a @c <code>MSG</code> command.
+          *
+          *  This method will read the remaining message data from the network
+          *  and then delegates to private @c message_* functions based on the
+          *  @c Content-Type header found in the message.
+          */
+        void handle_MSG(std::vector<std::string> & args);
+        
+        virtual void handleIncomingData() = 0;
+        
+        /** Dispatch a command to its appropriate handler routines based on @a 
args.
+         * 
+         *  @param  args  A vector of strings containing arguments, returned 
from readLine.
+         */
+        virtual void dispatchCommand(std::vector<std::string> & args) = 0;
+
+        /** Read a line from the network and split it into its components.
+         *
+         *  MSN commands and their arguments are separated by white space.
+         */
+        std::vector<std::string> getLine();
+        
+        bool isWholeLineAvailable();
+        bool bytesAvailable();
+        
+        /** Write a string to the connection.
+         *
+         */
+        virtual size_t write(std::string s, bool log=true) throw 
(std::runtime_error);
+        
+        /** Write the contents of a stringstream to the connection.
+         *    
+         * @param  s    The stringstream to write.
+         * @param  log  Should we log this output to the console.
+         *
+         * write will buffer the output if a connection has not yet been 
established.
+         * In this case, the data will be written as soon as a connection is 
+         * established.
+         */
+        virtual size_t write(std::ostringstream & s, bool log=true) throw 
(std::runtime_error);
+                
+        std::string writeBuffer;
+        static std::map<std::string, void 
(ConnectionImpl::*)(std::vector<std::string> &, std::string, std::string)> 
messageHandlers;
+        void message_plain(std::vector<std::string> & args, std::string mime, 
std::string body);
+        void message_initial_email_notification(std::vector<std::string> & 
args, std::string mime, std::string body);
+        void message_email_notification(std::vector<std::string> & args, 
std::string mime, std::string body);
+        void message_invitation(std::vector<std::string> & args, std::string 
mime, std::string body);
+        void message_typing_user(std::vector<std::string> & args, std::string 
mime, std::string body);
+    };
+}

Copied: trunk/msn/impl/filetransfer.cpp (from rev 356, 
trunk/msn/filetransfer.cpp)
===================================================================
--- trunk/msn/filetransfer.cpp  2005-07-11 23:24:29 UTC (rev 356)
+++ trunk/msn/impl/filetransfer.cpp     2005-07-12 03:08:54 UTC (rev 359)
@@ -0,0 +1,531 @@
+/*
+ * filetransfer.cpp
+ * libmsn
+ *
+ * Created by Mark Rowe on Wed Mar 17 2004.
+ * Copyright (c) 2004 Mark Rowe. 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 <msn/filetransfer.h>
+#include "filetransfer.h"
+#include <msn/message.h>
+#include <msn/errorcodes.h>
+#include <msn/externals.h>
+#include <msn/notificationserver.h>
+#include <msn/switchboardserver.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#else
+#include <winsock.h>
+#include <io.h>
+#endif
+
+#include <sstream>
+#include <cerrno>
+#include <cassert>
+
+namespace MSN 
+{
+    static const unsigned int MAX_FTP_BLOCK_SIZE = 20000;
+    
+    void FileTransferInvitationImpl::invitationWasAccepted(const std::string & 
body)
+    {
+        if (this->invitationWasSent())
+        {
+            this->sendFile(body);
+        }
+        else
+        {
+            this->receiveFile(body);
+        }
+    }
+    
+    void FileTransferInvitationImpl::invitationWasCanceled(const std::string & 
body)
+    {
+//        
this->switchboardConnection()->myNotificationServer()->externalCallbacks.fileTransferFailed(this,
 0, "Cancelled by remote user");
+        if (this->invitationWasSent())
+        {
+//            this->switchboardConnection()->invitationsSent.remove(this);
+        }
+        else 
+        {
+//            this->switchboardConnection()->invitationsReceived.remove(this);
+        }
+//        this->switchboardConnection()->removeFileTransferConnection(this);
+    }
+    
+    void FileTransferInvitationImpl::sendFile(const std::string & msg_body)
+    {
+        int port = 6891;
+        char tmp[64];
+        sprintf(tmp, "%d", rand());
+//        FileTransferConnection * conn = new 
FileTransferConnection(this->switchboardConnection()->auth.username, 
+//                                                                   
std::string(tmp), FileTransferConnectionImpl::MSNFTP_SEND, this);
+        
+//        
this->switchboardConnection()->myNotificationServer()->externalCallbacks.fileTransferProgress(this,
 "Sending IP address", 0, 0);
+        
+//        while((conn->sock = 
this->switchboardConnection()->myNotificationServer()->externalCallbacks.listenOnPort(port))
 < 0)
+        {
+            port++;
+            if (port > 6911)
+            {
+//                
this->switchboardConnection()->myNotificationServer()->externalCallbacks.fileTransferFailed(this,
 errno, strerror(errno));
+//                this->switchboardConnection()->invitationsSent.remove(this);
+//                conn->disconnect();
+                return;
+            }
+        }
+        
+//        
this->switchboardConnection()->myNotificationServer()->externalCallbacks.registerSocket(conn->sock,
 1, 0);
+        
+//        this->switchboardConnection()->addFileTransferConnection(conn);
+        
+        std::ostringstream buf_;
+        buf_ << "Invitation-Command: ACCEPT\r\n";
+        buf_ << "Invitation-Cookie: " << this->cookie << "\r\n";
+//        buf_ << "IP-Address: " << 
this->switchboardConnection()->myNotificationServer()->externalCallbacks.getOurIP()
 << "\r\n";
+        buf_ << "Port: " << port << "\r\n";
+//        buf_ << "AuthCookie: " << conn->auth.cookie << "\r\n";
+        buf_ << "Launch-Application: FALSE\r\n";
+        buf_ << "Request-Data: IP-Address:\r\n";
+        buf_ << "\r\n";
+        
+        Message * msg = new Message(buf_.str());
+        msg->setHeader("Content-Type", "text/x-msmsgsinvite; charset=UTF-8");
+//        this->switchboardConnection()->sendMessage(msg);
+        delete msg;
+    }
+    
+    void FileTransferInvitationImpl::receiveFile(const std::string & msg_body)
+    {
+        Message::Headers headers(msg_body);
+        std::string cookie = headers["AuthCookie"];
+        std::string remote = headers["IP-Address"];
+        std::string port_c = headers["Port"];
+        int port;
+        
+        if (cookie.empty() || remote.empty() || port_c.empty())
+        {
+//            
this->switchboardConnection()->myNotificationServer()->externalCallbacks.fileTransferFailed(this,
 0, "Missing parameters");
+//            this->switchboardConnection()->invitationsReceived.remove(this);
+            return;
+        }
+        
+        port = decimalFromString(port_c);
+//        FileTransferConnection * conn = new 
FileTransferConnection(this->switchboardConnection()->auth.username,
+//                                                                   cookie, 
FileTransferConnectionImpl::MSNFTP_RECV, this);
+        
+        std::ostringstream buf_;
+        buf_ << "Connecting to " << remote << ":" << port << "\n";
+//        
this->switchboardConnection()->myNotificationServer()->externalCallbacks.fileTransferProgress(this,
 buf_.str(), 0, 0);
+        
+//        conn->sock = 
this->switchboardConnection()->myNotificationServer()->externalCallbacks.connectToServer(remote,
 port, &conn->connected);
+        
+//        if (conn->sock < 0)
+        {
+//            
this->switchboardConnection()->myNotificationServer()->externalCallbacks.fileTransferFailed(this,
 errno, strerror(errno));
+//            this->switchboardConnection()->invitationsReceived.remove(this);
+            return;
+        }
+
+//        if (! conn->isConnected())
+//            
this->switchboardConnection()->myNotificationServer()->externalCallbacks.registerSocket(conn->sock,
 0, 1);
+//        else
+//            
this->switchboardConnection()->myNotificationServer()->externalCallbacks.registerSocket(conn->sock,
 1, 0);
+        
+//        
this->switchboardConnection()->myNotificationServer()->externalCallbacks.fileTransferProgress(this,
 "Connected", 0, 0);
+//        this->switchboardConnection()->addFileTransferConnection(conn);
+        
+//        conn->write("VER MSNFTP\r\n");
+    }
+    
+    void FileTransferConnectionImpl::disconnect()
+    {
+        // self_.ConnectionImpl::disconnect();
+        
+//        if (this->auth.fd)
+        {
+//            fclose(this->auth.fd);
+//            this->auth.fd = NULL;
+        }
+        
+//        
this->auth.inv->switchboardConnection()->removeFileTransferConnection(this);
+//        delete this->auth.inv;
+//        this->auth.inv = NULL;
+    }
+    
+    FileTransferConnectionImpl::~FileTransferConnection()
+    {
+        this->disconnect();
+    }
+    
+    void FileTransferConnectionImpl::socketConnectionCompleted()
+    {
+//        self_.ConnectionImpl::socketConnectionCompleted();
+//        
this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock);
+//        
this->myNotificationServer()->externalCallbacks.registerSocket(this->sock, 1, 
0);
+    }    
+    
+    void FileTransferConnectionImpl::socketIsWritable()
+    {
+//        if (this->auth.direction == MSNFTP_SEND)
+//            this->handleSend();
+    }
+    
+    void FileTransferConnectionImpl::dataArrivedOnSocket()
+    {
+//        if (this->auth.direction == MSNFTP_SEND && ! this->auth.connected)
+//            this->handleSend();
+//        else
+//            self_.ConnectionImpl::dataArrivedOnSocket();
+    }
+    
+    void FileTransferConnectionImpl::handleIncomingData()
+    {
+//        if (this->auth.direction == MSNFTP_RECV)
+//            this->handleReceive();
+//        else 
+//            this->handleSend();
+    }
+    
+    void FileTransferConnectionImpl::handleSend()
+    {
+//        if (! this->auth.connected) // we have not accept()ed yet, but the 
read/writability means there's one waiting
+//        {
+//            this->handleSend_WaitingForConnection();
+//        } 
+//        else if (this->auth.fd == NULL)
+//        {
+//            this->handleSend_Negotiating();
+//        }
+//        else if (this->auth.inv->fileSize != this->auth.bytes_done)
+//        {
+//            this->handleSend_Transferring();
+//        }
+//        else
+        {
+            this->handleSend_Bye();
+        }
+    }
+    
+    void FileTransferConnectionImpl::handleSend_WaitingForConnection()
+    {
+        int s;
+        
+        if ((s = accept(this->sock, NULL, NULL)) < 0)
+        {
+            perror("Could not accept()\n");
+//            
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
+//            
this->auth.inv->switchboardConnection()->invitationsSent.remove(this->auth.inv);
+            return;
+        }
+        
+//        
this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock);
+        close(this->sock);
+        
+        this->sock = s;
+//        
this->myNotificationServer()->externalCallbacks.registerSocket(this->sock, 1, 
0);
+        
+//        
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Connected", 0, 0);
+        
+//        this->auth.connected = 1;
+        this->connected = true;        
+    }
+    
+    void FileTransferConnectionImpl::handleSend_Negotiating()
+    {
+//        if (! this->isWholeLineAvailable())
+//            return;
+        
+//        std::vector<std::string> args = this->getLine();
+//        this->readBuffer = 
this->readBuffer.substr(this->readBuffer.find("\r\n") + 2);
+                
+//        if (args[0] == "VER")
+        {
+//            if (this->write("VER MSNFTP\r\n") != strlen("VER MSNFTP\r\n"))
+//                return;
+//            
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Negotiating", 0, 0);
+        }
+//        else if (args[0] == "USR")
+        {
+//            if (args[2] != this->auth.cookie)  // if they DIFFER
+            {
+//                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
+//                
this->auth.inv->switchboardConnection()->invitationsSent.remove(this->auth.inv);
+                return;
+            }
+            std::ostringstream buf_;
+//            buf_ << "FIL " << this->auth.inv->fileSize << "\r\n";
+//            this->write(buf_);
+        }
+//        else if (args[0] == "TFR")
+        {
+            // you asked for it, go to data-dump mode
+//            this->auth.fd = fopen(this->auth.inv->fileName.c_str(), "r");
+//            if (this->auth.fd == NULL)
+            {
+                perror("fopen() failed");
+//                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, "Could not open file for reading");
+//                
this->auth.inv->switchboardConnection()->invitationsSent.remove(this->auth.inv);
+                return;
+            }
+            
+            // OK, now we lose control, but the next round of the polling loop 
will
+            // say that the socket is writable, and then the fun starts...
+//            
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Sending data", 0, 0);
+//            
this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock);
+//            
this->myNotificationServer()->externalCallbacks.registerSocket(this->sock, 0, 
1);                        
+        }
+    }
+    
+    void FileTransferConnectionImpl::handleSend_Transferring()
+    {
+        // just pumping data now
+        
+        fd_set writefd;
+        FD_ZERO(&writefd);
+        FD_SET(this->sock, &writefd);
+        struct timeval tout={0, 0};
+        unsigned char *readBuffer = (unsigned char *) 
calloc(MAX_FTP_BLOCK_SIZE, sizeof(unsigned char));
+        
+        if (select(this->sock + 1, NULL, &writefd, NULL, &tout) == 1)
+        {
+            int bytesWritten = 0;
+            unsigned int blockLength;
+            unsigned char blockHeader[3];
+//            unsigned int bytesRemaining = this->auth.inv->fileSize - 
this->auth.bytes_done;
+//            blockLength = bytesRemaining > MAX_FTP_BLOCK_SIZE / 4 ? 
MAX_FTP_BLOCK_SIZE / 4 : bytesRemaining;
+            if (blockLength == 0)
+                blockHeader[0] = 1;
+            else
+                blockHeader[0] = 0;
+            blockHeader[1] = (blockLength >> 0) & 0xff;
+            blockHeader[2] = (blockLength >> 8) & 0xff;
+            
+//            if (this->write(std::string((char *) &blockHeader[bytesWritten], 
3 - bytesWritten), false) != 3)
+//            {
+//                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
+//                goto cleanup;
+//            }
+            
+//            if (fread(readBuffer, sizeof(unsigned char), blockLength, 
this->auth.fd) < 0)
+//            {
+//                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
+//                goto cleanup;
+//            }
+            
+//            if ((blockLength = this->write(std::string((char *) readBuffer, 
blockLength), false)) < 0)
+//            {
+//                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
+//                goto cleanup;
+//            }
+//            this->auth.bytes_done += blockLength;
+        }
+        free(readBuffer);
+//        
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Sending file", this->auth.bytes_done, this->auth.inv->fileSize);
+        return;
+cleanup:
+            ;
+//        
this->auth.inv->switchboardConnection()->invitationsSent.remove(this->auth.inv);
+        if (readBuffer)
+            free(readBuffer);
+//        if (this->auth.fd)
+//        {
+//            fclose(this->auth.fd);
+//            this->auth.fd = NULL;
+//        }
+    }
+    
+    void FileTransferConnectionImpl::handleSend_Bye()
+    {
+//        
this->myNotificationServer()->externalCallbacks.fileTransferSucceeded(this->auth.inv);
+        
+//        
this->auth.inv->switchboardConnection()->invitationsSent.remove(this->auth.inv);
+        this->disconnect();
+    }
+    
+    
+    void FileTransferConnectionImpl::handleReceive()
+    {
+//        if (this->auth.fd == NULL)
+//            this->handleReceive_Negotiating();
+//        else
+//            this->handleReceive_Transferring();
+    }
+    
+    void FileTransferConnectionImpl::handleReceive_Negotiating()
+    {
+//        if (! this->isWholeLineAvailable())
+//            return;
+                
+//        std::vector<std::string> args = this->getLine();
+//        this->readBuffer = 
this->readBuffer.substr(this->readBuffer.find("\r\n") + 2);        
+        
+//        if (args[0] == "VER")
+        {
+            std::ostringstream buf_;
+//            buf_ << "USR " << this->auth.username << " " << 
this->auth.cookie << "\r\n";
+//            this->write(buf_);
+//            
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Negotiating", 0, 0);
+            return;
+        } 
+//        else if (args[0] == "FIL")
+        {
+//            this->auth.fd = fopen(this->auth.inv->fileName.c_str(), "w");
+//            if (this->auth.fd == NULL)
+//                goto error;
+            
+//            this->write("TFR\r\n");
+        }
+        return;
+error:
+            ;
+//        
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 errno, strerror(errno));
+//        
this->switchboardConnection()->invitationsReceived.remove(this->auth.inv);
+    }
+    
+    void FileTransferConnectionImpl::handleReceive_Transferring()
+    {
+        // Each block has a 3-byte header
+        // 0: either 1 or 0.  0 means data block, 1 means transfer completed.
+        // 1: Low byte of block length
+        // 2: High byte of block length
+        
+        unsigned int blockLength;
+        std::string blockHeader;
+        
+        while (1)
+        {
+//            if (this->readBuffer.size() < 3)
+//                return;
+            
+            // read the three byte header
+//            blockHeader = this->readBuffer.substr(0, 3);
+            if (blockHeader[0] == 1U)
+            {
+                // Transfer completed block
+                if (blockHeader[1] != 0 || blockHeader[2] != 0)
+                {
+//                    
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 0, "Invalid block header.\n");
+                    goto cleanup;
+                }
+//                this->write("BYE 16777989\r\n");
+//                
this->myNotificationServer()->externalCallbacks.fileTransferSucceeded(this->auth.inv);
+                
+                goto cleanup;
+            }
+            else if (blockHeader[0] != 0U)
+            {
+//                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 0, "Invalid block header.");
+                goto cleanup;
+            }
+            
+            // Read the entire block
+            blockLength = ((unsigned char) blockHeader[1]) | ((unsigned char) 
blockHeader[2]) << 8;
+            if (blockLength > MAX_FTP_BLOCK_SIZE)
+            {
+//                
this->myNotificationServer()->externalCallbacks.fileTransferFailed(this->auth.inv,
 0, "Block size greater than largest expected block size.");
+                goto cleanup;
+            }
+            
+//            if (this->readBuffer.size() < 3 + blockLength)
+//                return;
+            
+//            std::string block = this->readBuffer.substr(3, blockLength);
+//            this->readBuffer = this->readBuffer.substr(3 + blockLength);
+            
+//            fwrite(block.c_str(), sizeof(unsigned char), block.size(), 
this->auth.fd);
+//            this->auth.bytes_done += blockLength;
+            
+//            if (this->auth.bytes_done == this->auth.inv->fileSize)
+            {
+                // It appears that sometimes the 1,0,0 block header
+                // that indicates success isnt sent...
+                
+//                this->write("BYE 16777989\r\n");
+//                
this->myNotificationServer()->externalCallbacks.fileTransferSucceeded(this->auth.inv);
+                goto cleanup;
+            }
+//            
this->myNotificationServer()->externalCallbacks.fileTransferProgress(this->auth.inv,
 "Receiving file", this->auth.bytes_done, this->auth.inv->fileSize);
+        }
+        return;
+cleanup:
+            ;
+//        
this->auth.inv->switchboardConnection()->invitationsReceived.remove(this->auth.inv);
+//        if (this->auth.fd)
+        {
+//            fclose(this->auth.fd);
+//            this->auth.fd = NULL;
+        }
+    }
+    
+    void FileTransfe