//kircserver.cpp
//handles socket connections, server messages
//Aaron Granick

#include "server.moc"
#include "server.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <kmsgbox.h>
#include <iostream.h>
#include <qdatetm.h>
#include <time.h>
#include <signal.h>
#include "ircapp.h"
#include "client.h"

Server::Server ( QObject *parent, const char *name, int serverPort)
        : QObject (parent, name)
{
    connected = FALSE; // we are not connected yet
    registered = false; // nor are we registered
    port = serverPort;
    if (port == 0)
        port = DEFAULT_PORT;
    incomplete = "";
    rsn = NULL;
    wsn = NULL;
}


int Server::Connect ( )
{
    cout << "connecting.\n";
    char str[600];
    int fd;
    struct sockaddr_in sin;
    struct hostent* hostent;
    struct protoent* p;

    bzero(str, 600);

    // clean up after ourselves
    if (rsn)
        delete rsn;
    if (wsn)
        delete wsn;
    
    sprintf(str, "Connecting to port %d of server %s", port, name());

    app->HandleEvent ( Event::INTERNAL_MESSAGE, str);

    app->UpdateAll (); // give us at least time to print stuff out
    
    if ((hostent = gethostbyname(name())) == NULL)
    {
	KMsgBox::message(0, "Get host for server",
		"The server you tried to connect to does\n"
		"not have a DNS entry, or the DNS server\n"
		"containing the server's information is\n"
		"not responding (or your link is dead.)", KMsgBox::STOP);
	return 0;
    }

    bzero((char *) &sin, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    bcopy(hostent->h_addr, (char *) &sin.sin_addr, hostent->h_length);

    p = getprotobyname("tcp");

    fd = socket(AF_INET, SOCK_STREAM, 0);
    fcntl(fd, F_SETFL, O_NONBLOCK); // make the socket non-blocking
    ::connect(fd, (struct sockaddr *) &sin, sizeof(sin));

    rsn = new QSocketNotifier(fd, QSocketNotifier::Read);
    wsn = new QSocketNotifier(fd, QSocketNotifier::Write);

    QObject::connect(rsn, SIGNAL(activated(int)), this, SLOT(ReadData()));
    QObject::connect(wsn, SIGNAL(activated(int)), this, SLOT(WriteData()));

    rsn->setEnabled(TRUE);
    wsn->setEnabled(TRUE);

    app->HandleEvent ( Event::INTERNAL_MESSAGE, "Connected.");
    app->HandleEvent ( Event::CONNECTED, NULL);
    connected = true;
    
    return 1;
}			


int Server::Send ( const char *buff )
{
    if (!connected)
    {
        app->HandleEvent(Event::INTERNAL_MESSAGE, "You are not on a server.");
        return 0;
    }
    write(wsn->socket(), buff, strlen(buff));

    if (Settings::debug)
        cout << "Sent " << buff << " to server\n";

    return 1;
   
}

void Server::ReadData()
{
     if (Settings::debug)
         cout << "Reading data from server....\n";
    char dat[8192];
    int len;

    bzero(dat, 8192);

    len = read(rsn->socket(), dat, 8192);
    if (len <= 0) {
        cout << "recieved eof.\n";
	app->HandleEvent ( Event::INTERNAL_MESSAGE, "Disconnected.");
	rsn->setEnabled(FALSE);
	wsn->setEnabled(FALSE);
        connected = FALSE;
        app->HandleEvent(Event::DISCONNECTED, NULL);
    }
    else
    {
        if (Settings::echo)
            cout << dat << "\n";
        // ProcessData(dat);

        QString str(dat);
        str.prepend(incomplete); // tack on anything we might be missing
        incomplete = "";
        while (str != "")
        {
            int i = str.find("\n");
            if (i > -1)
            {
                // cout << "Processing: " << str.left(i+1);
                Client::ParseServer(str.left(i+1));
                str = str.right(str.size()-i-2);
            }
            else
            {
                incomplete = str;
                str = "";
            }
        }
                          
    }
}

void Server::WriteData()
{
    signal(SIGPIPE,SIG_IGN);  // capture broken pipes
       
    if (Settings::debug)
        cout << "writing data to socket.\n";
    char str[600];

    bzero(str, 600);
    sprintf(str, "USER %s kde.com kde.com :%s\r\n",
	(const char *)(Me->Name()), (const char *)(Me->Info()));

    int i =  write(wsn->socket(), str, strlen(str));
    if (i == -1)
    {
        wsn->setEnabled(FALSE);
        return;
    }
   
    bzero(str, 600);
    sprintf(str, "NICK %s\r\n", (const char *)(Me->Nick()));
    i = write(wsn->socket(), str, strlen(str));
    if (i == -1)
    {
        wsn->setEnabled(FALSE);
        return;
    }
    
    wsn->setEnabled(FALSE);
}


void Server::Disconnect ( const char *quitMsg)
{
    cout << "disconnecting from server....\n";
    if (!connected)
    {
        cout << "cannot disconnect from server: you are not connected.\n";
        return;
    }
    char msg[512];
    bzero (msg, 512);
    if (!quitMsg)
        sprintf ( msg, "QUIT :%s\r\n", (const char *)Settings::quitMessage );
    else
        sprintf ( msg, "QUIT :%s\r\n", quitMsg );
    Send (msg);
    connected = false;
}

