Chat-O-Matic/libs/libmsn/connection.cpp

242 lines
8.0 KiB
C++

/*
* connection.cpp
* libmsn
*
* Created by Mark Rowe on Mon Mar 22 2004.
* Refactored by Tiago Salem Herrmann on 08/2007.
* Copyright (c) 2004 Mark Rowe. All rights reserved.
* Copyright (c) 2007 Tiago Salem Herrmann. All rights reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <connection.h>
#include <errorcodes.h>
#include <util.h>
#include <passport.h>
#include <externals.h>
#include <notificationserver.h>
#ifndef WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#else
#include <winsock.h>
#include <io.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cerrno>
#include <time.h>
#include <cassert>
namespace MSN
{
static std::vector<std::string> errors;
Connection::Connection()
: sock(NULL), connected(false), trID(1)
{
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[241] = "Unable to add user";
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] = "Email Address Not verified";
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";
errors[921] = "Error synchronizing lists";
errors[922] = "Error synchronizing address book";
}
}
Connection::~Connection() { }
void Connection::disconnect()
{
this->connected = false;
this->myNotificationServer()->externalCallbacks.unregisterSocket(this->sock);
this->myNotificationServer()->externalCallbacks.closeSocket(this->sock);
this->sock = NULL;
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;
if(this->writeBuffer.size())
{
// We know that we are connected, so this will try writing to the network.
size_t writtenLength = this->write(this->writeBuffer, 1);
if(writtenLength > 0 && this->writeBuffer.size() > 0)
this->writeBuffer = this->writeBuffer.substr(writtenLength);
}
}
size_t Connection::write(std::string s, bool log) throw (std::runtime_error)
{
if(s.size() < 0)
return 0;
if (! this->connected)
{
this->writeBuffer.append(s);
}
else
{
if (log)
this->myNotificationServer()->externalCallbacks.log(1, s.c_str());
char *a = (char*)s.c_str();
size_t written = this->myNotificationServer()->
externalCallbacks.writeDataToSocket(sock, a, (int) (s.size()));
return written;
}
return s.size();
}
size_t Connection::write(std::ostringstream & ss, bool log) throw (std::runtime_error)
{
std::string s = ss.str();
#ifdef DEBUG
std::cout << s << std::endl;
#endif
size_t result = write(s, log);
return result;
}
void Connection::dataArrivedOnSocket()
{
char tempReadBuffer[8192];
int amountRead = 8192;
std::string tempRead;
while (amountRead == 8192)
{
amountRead = this->myNotificationServer()->externalCallbacks.getDataFromSocket(sock, tempReadBuffer, 8192);
if(amountRead < 0)
break;
tempRead+= std::string(tempReadBuffer,amountRead);
}
if (tempRead.length() < 0)
{
// We shouldn't be 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, "No data to read");
this->disconnect();
}
else if (amountRead == 0)
{
this->myNotificationServer()->externalCallbacks.showError(this, "Connection closed by remote endpoint.");
this->disconnect();
}
else
{
this->readBuffer += tempRead;
#ifdef DEBUG
std::cout << tempRead << std::endl;
#endif
try
{
handleIncomingData();
}
catch (std::exception & e)
{
this->myNotificationServer()->externalCallbacks.showError(this, e.what());
}
}
}
void Connection::showError(int errorCode)
{
std::ostringstream buf_;
buf_ << "Error code: " << errorCode << " (" << errors[errorCode] << ")";
this->myNotificationServer()->externalCallbacks.showError(this, buf_.str());
}
}