/***************************************************************************
                          c6proto.cpp  -  description
                             -------------------
    begin                : Wed Feb 19 2003
    copyright            : (C) 2003 by Giorgio A.
    email                : openc6@hotmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "c6proto.h"
#include "protosupport.h"
#include <qhostaddress.h>
#include <qstringlist.h>
#include <qfile.h>
#include <vector>
#include "c6logger.h"
#include "c6settings.h"
#include "c6proxysocket.h"
#include "c6utils.h"
#include "c6httpconnection.h"
#include <qregexp.h>
#include <qvariant.h>
#include <qmap.h>

#define PROTO_SIG "C6PROTO:"
#define XFER_SIG "XFERPROTO:"

#define MAXNICKLEN 18
#define MAXNICKBLOB 80
#define INCOMING_FILE_ID 0x0403

#define DUMP_RECEIVED_PACKET do {\
  int len;\
  C6Utils::safeShortRead(data+4,&len,data+6);\
  C6Utils::dumpPacket(PROTO_SIG,data,len+6);\
} while(0)

#define MAX_PTR(len) (data+PACKET_HEADER_LEN+len-1)

#define REQUEST_FILE_STR(filename) QString("Vuoi ricevere il file "+filename+" ? c6cmd://Accept?Type=FILE&Value=YES c6cmd://Accept?Type=FILE&Value=NO")
#define RECEIVE_ON QString("Ricezione automatica abilitata")
#define AUTH_ACCEPT_STR "vuole inserirti nella sua lista amici. Accetti ? c6cmd://Accept?Type=AUTH&Value=YES c6cmd://Accept?Type=AUTH&Value=NO"    
#define WARN_ACCEPT_STR "ti ha inserito nella sua lista amici."    

class BufferInfo
{
    public:   
        unsigned char* pBuffer;    
        int packetLength;
        int packetOwnerLength;    
};

static const char* statusProfile[] =
    {"Occupato","Disponibile","Solo Amici","Non in linea","Assente","Stato sconosciuto",0
    };

typedef std::vector<C6Proto::Category> CategoryVector;           

std::vector<QString> profileRequestDB;
C6HttpConnection *httpUriFetch= 0;
C6HttpConnection *httpCategoryFetch = 0;
CategoryVector categoryVector;
std::vector<BufferInfo> g_bufferVector;

C6Proto::C6Proto(QObject *parent) : QObject(parent)
        ,_pSocket(0)
        , BannerDataP(0)
        ,_ipVisible(false)
        ,_oldAccount(false)
        ,_initStatus(C6Users::U_NOTPRESENT)
        ,_hasNAT(false)
        ,_xcapHandler(new C6XCAPClient())
        ,_gatewayList(new QStringList())
{
    connect(_xcapHandler,SIGNAL(buddyAuthReady(QByteArray &)),SLOT(buddyAuthSlot(QByteArray &)));   
    connect(_xcapHandler,SIGNAL(buddyListReady(QByteArray &)),SLOT(buddyListSlot(QByteArray &))); 
    connect(_xcapHandler,SIGNAL(buddyConfigReady(QByteArray &)),SLOT(buddyConfigSlot(QByteArray &)));                  
    connect(_xcapHandler,SIGNAL(xcapResponseOK(C6XCAPClient::XCAP_STATE)),SLOT(xcapResponseOKSlot(C6XCAPClient::XCAP_STATE)));
}

C6Proto::~C6Proto()
{
    delete _xcapHandler;
    delete _gatewayList;        
    delete _pSocket;
}
#define C6DEBUG

C6Users::C6USER_STATUS C6Proto::mapPS2US(int status)
{
    C6Users::C6USER_STATUS ret = C6Users::U_OFFLINE;

    if (status != 0)
    {      
        status&=0x000001ff;

        if (status & C6Proto::FREE)
        {
            ret = C6Users::U_AVAILABLE;
        }
        else
            if (status & C6Proto::NETFRIEND)
            {
                ret = C6Users::U_NETFRIENDONLY;
            }
            else
                if (status & C6Proto::BUSY)
                {
                    ret = C6Users::U_BUSY;
                }

        if (status & C6Proto::AWAY)
        {
            ret = C6Users::U_AWAY;
        }
    }
    
    return(ret);
}

int C6Proto::mapUS2PS(C6Users::C6USER_STATUS status)
{
    int ret = C6Proto::OFF_LINE;

    switch(status)
    {
    case C6Users::U_AVAILABLE:
        ret = C6Proto::FREE;
        break;
    case C6Users::U_AWAY:
        ret = C6Proto::AWAY;
        break;
    case C6Users::U_BUSY:
        ret = C6Proto::BUSY;
        break;
    case C6Users::U_NETFRIENDONLY:
        ret = C6Proto::NETFRIEND;
        break;
    default:
        break;
    }

    return(ret);
}

const char* C6Proto::getStatusString(unsigned int status)
{
    const char* ptr=statusProfile[3];
    status&=0x000001ff;

    if ((status == 0x1ff) || (status == 0))
    {
        ptr=statusProfile[3];
    }
    else
    {      
        if (status & FREE)
        {
            ptr =  statusProfile[1];
        }
        else
        {         
            if (status & NETFRIEND)
            {
                ptr = statusProfile[2];
            }
            else
            {            
                if (status & BUSY)
                {
                    ptr = statusProfile[0];
                }
            }         
        }
        
        if (status & AWAY)
        {
            ptr = statusProfile[4];
        }
    }
    return(ptr);
}


int C6Proto::parseAggregate(unsigned char* ptr,const unsigned char* maxPtr,int &fieldLength,QVariant &variant)
{
    unsigned char *savePtr = ptr;    
    
    if (fieldLength == 0)
    {      
        C6Utils::safeShortRead(ptr,&fieldLength,maxPtr);
        ptr+=2;        
    }      
    
    ptr+=2;     
    
    int fieldType = -1;     
    C6Utils::safeByteRead(ptr,&fieldType,maxPtr);
    ptr++; 
    
    switch(fieldType)
    {
        case AGGREGATE_INT:
        {
            int intfieldHi; 
            int intfieldLo;          
            C6Utils::safeShortRead(ptr,&intfieldHi,maxPtr);
            ptr+=2; 
            C6Utils::safeShortRead(ptr,&intfieldLo,maxPtr);
            ptr+=2;          
            variant = QVariant(intfieldLo | (intfieldHi << 16));
        }         
        break;
        case AGGREGATE_STRING:
        {         
            int len = -1; 
            C6Utils::safeByteRead(ptr,&len,maxPtr);
            ptr++; 
            
            unsigned char *str = new unsigned char[len+1]; 
            
            C6Utils::safeStringCopy(str,ptr,len,maxPtr);     
            str[len] = 0; 
            
            variant = QVariant(QString::fromAscii(const_cast<char*>(reinterpret_cast<char*>(str)))); 
            ptr+=len; 
            delete [] str;         
        }         
        break;         
        case AGGREGATE_BYTE:
            break;         
        case AGGREGATE_SHORT:
            break;         
        case AGGREGATE_TIME:
            break;         
        case AGGREGATE_TEXT:
            break;         
        case AGGREGATE_USER_DEFINED:
            break;         
        default:
            break;         
    }       
             
    return(ptr-savePtr);   
}      

void C6Proto::writeAggregate(std::vector<char> &data,int fieldNo,int &fieldCounter,QVariant &variant)
{
    if (fieldCounter == 0)
    {
        data.push_back(static_cast<char>(fieldNo >> 8));
        data.push_back(static_cast<char>(fieldNo & 0x000000FF));            
    }      
    
    fieldCounter++;         
    
    bool ok = false;    
    int dataInt = variant.toInt(&ok);   
    
    data.push_back(static_cast<char>(fieldCounter >> 8));
    data.push_back(static_cast<char>(fieldCounter & 0x000000FF));    
       
    if (ok == true)    
    {
        data.push_back(static_cast<char>(AGGREGATE_INT));    
        data.push_back(static_cast<char>((dataInt >> 24) & 0x000000FF));
        data.push_back(static_cast<char>((dataInt >> 16) & 0x000000FF));     
        data.push_back(static_cast<char>((dataInt >> 8) & 0x000000FF));
        data.push_back(static_cast<char>(dataInt & 0x000000FF));     
    } 
    else
    {
        QString dataStr = variant.toString();
            
        if (dataStr != QString::null)
        {
            data.push_back(static_cast<char>(AGGREGATE_STRING));        
            data.push_back(static_cast<char>(dataStr.length()));    
            for (unsigned int i=0; i < dataStr.length(); i++)
            {
                data.push_back(dataStr.at(i).latin1());  
            }            
        }
        else
        {
        }                   
    }     
}      

void C6Proto::createSocket()
{
    C6Settings &settings =  C6Settings::getInstance();

    if (settings.getProxySwitch() == false)
    {
        if (_pSocket != 0)
        {
            delete _pSocket;
        }

        _pSocket = new QSocket(this);
        connect(_pSocket,SIGNAL(connected()),SLOT(socket_Connected()));
        connect(_pSocket,SIGNAL(readyRead()),SLOT(socket_ReadyRead()) );
        connect(_pSocket,SIGNAL(error(int)),SLOT(socket_Error(int)) );
        connect(_pSocket,SIGNAL(bytesWritten(int)),SLOT(socket_bytesWritten(int)));
        connect(_pSocket,SIGNAL(connectionClosed ()),SLOT(socket_connectionClosed()));
    }
    else
    {
        if (_pSocket)
        {
            delete static_cast<C6ProxySocket*>(_pSocket);
        }

        const bool hasAccount = settings.getAuthProxySwitch();
        const bool isSocks4 = settings.getProxySocksVersion() ? false : true;
        char *pUserId = 0;
        char *pUserPsw = 0;

        if (hasAccount == true)
        {
            pUserId = const_cast<char*>(settings.getProxyUserId().latin1());
            pUserPsw = const_cast<char*>(settings.getProxyUserPsw().latin1());
        }

        _pSocket = new C6ProxySocket(this,isSocks4,hasAccount,const_cast<char*>(pUserId),const_cast<char*>(pUserPsw));

        connect(_pSocket,SIGNAL(error(int)),SLOT(socket_Error(int)) );
        connect(_pSocket,SIGNAL(connectionClosed ()),SLOT(socket_connectionClosed()));
        connect(_pSocket,SIGNAL(proxyError(int)),SLOT(proxyError(int)));
        connect(_pSocket,SIGNAL(proxyConnected()),SLOT(proxyConnected()));
    }
}

void C6Proto::startConnection(QString const & nick,QString const & pwd)
{
    Q_ASSERT(_initStatus != C6Users::U_NOTPRESENT);

    C6Settings &settings = C6Settings::getInstance();
    QString server = settings.getServerName();
    QString port = settings.getServerPort();

    firstLogin = nick;
    firstPassword = pwd;

    _previousStatus = C6Users::U_NOTPRESENT;
    infoLoginFlag = false;
    _socketStatusProgress = 0;

    createSocket();

    if (settings.getProxySwitch() == true)
    {
        C6ProxySocket *pProxySocket = static_cast<C6ProxySocket*>(_pSocket);
        pProxySocket->setDestConnection(server,port);
        server = settings.getProxyName();
        port = settings.getProxyPort();
        pProxySocket->connectToHost(server,(Q_UINT16)port.toInt());
    }
    else
    {
        _pSocket->connectToHost(server,(Q_UINT16)port.toInt());
    }

    emit SysLog("Connecting to "+server+":"+port);
}

void C6Proto::socket_Connected()
{
    _socketStatusProgress +=10;

    emit progress(_socketStatusProgress);
    emit SysLog("Socket Connected");
}

void C6Proto::socket_ReadyRead()
{
    int avail = _pSocket->bytesAvailable();
    unsigned char* incomingBuffer = 0;
    bool packetComplete = false;
    
    int count = g_bufferVector.size(); 
        
    if (count > 0)
    {
        int remaining = g_bufferVector[count - 1].packetLength - g_bufferVector[count - 1].packetOwnerLength;       
        if (avail >= remaining)
        {
            unsigned char* completeBuffer = new unsigned char[g_bufferVector[count - 1].packetOwnerLength+6+remaining];
            memcpy(completeBuffer,g_bufferVector[count - 1].pBuffer,g_bufferVector[count - 1].packetOwnerLength+6);
            _pSocket->readBlock(reinterpret_cast<char*>(completeBuffer+g_bufferVector[count - 1].packetOwnerLength+6),remaining);          
            delete [] g_bufferVector[count - 1].pBuffer;    
            g_bufferVector.pop_back();
           
            avail = g_bufferVector[count - 1].packetOwnerLength+remaining + 6;    
            incomingBuffer = completeBuffer;    
            packetComplete = true;             
        }
        else
        {
            incomingBuffer = new unsigned char [avail+g_bufferVector[count - 1].packetOwnerLength+6];
            memcpy(incomingBuffer,g_bufferVector[count - 1].pBuffer,g_bufferVector[count - 1].packetOwnerLength+6);
            _pSocket->readBlock(reinterpret_cast<char*>(incomingBuffer+g_bufferVector[count - 1].packetOwnerLength+6),avail);     
            delete [] g_bufferVector[count - 1].pBuffer;
            g_bufferVector[count - 1].pBuffer = incomingBuffer; 
            g_bufferVector[count - 1].packetOwnerLength +=avail;                    
            return;
        }                         
    }          
    else
    {      
        incomingBuffer = new unsigned char [avail];
        _pSocket->readBlock(reinterpret_cast<char*>(incomingBuffer),avail);  
    }      
    
    int commandID = incomingBuffer[0];
            
    if (commandID == SERVERID)
    {
        int packetCount;
        int packetLength;
            
        C6Utils::safeShortRead(incomingBuffer+2,&packetCount,incomingBuffer+4);
        C6Utils::safeShortRead(incomingBuffer+4,&packetLength,incomingBuffer+6);     
                                    
        if ((packetLength > avail - 6) && packetComplete == false)
        {
            BufferInfo buffer;
            buffer.pBuffer = incomingBuffer;
            buffer.packetLength = packetLength;
            buffer.packetOwnerLength = avail-6;                               
            g_bufferVector.push_back(buffer);
        }                
        else
        {
            commandActionHandler(incomingBuffer,avail);
        }            
    }
    else
    {
        qWarning("BAD ??????\n");     
    }               
 }


void C6Proto::socket_Error(int)
{
    emit signalError(SERVER_ERROR);
}

/** handle server messages */
void C6Proto::commandActionHandler(unsigned char *data,int avail)
{
    unsigned char *com = data;

#ifdef C6DEBUG
    int PackC;
    C6Utils::safeShortRead(com+2,&PackC,com+4);
#endif
    int packetLength;
    C6Utils::safeShortRead(com+4,&packetLength,com+6);

    if (*com == SERVERID)
    {
        com++;
#ifdef C6DEBUG

        C6Logger::getInstance().debugPrint(PROTO_SIG,"Server sent Command (0x%02x) - Packet Count (%04d) - Packet Length (%d bytes)\n",*com,PackC,packetLength);
#endif

        switch(*com)
        {
        case HELO:
            _socketStatusProgress+=10;
            emit progress(_socketStatusProgress);
            Helo(data,packetLength);
            break;
        case REROUTE:
            _socketStatusProgress+=10;
            emit progress(_socketStatusProgress);
            rerouteServer(data,packetLength);
            break;
        case WELCOME:
            welcome(data,packetLength);
            break;
        case INFOLOGIN:

            if (_socketStatusProgress <= 20)                              // this is when redirect is skipped
            {
                _socketStatusProgress+=45;
            }
            else
            {
                _socketStatusProgress+=25;
            }

            emit progress(_socketStatusProgress);
            infoLogin(data,packetLength);
            break;
        case SND_USERS:
            SendUsers(data,packetLength);

            if (_socketStatusProgress <=100)
            {
                _socketStatusProgress+=35;
                emit progress(_socketStatusProgress);
            }
            break;
        case STATUS:
            userStatus(data,packetLength);
            break;
        case IN_CRYP_MESSAGE:
            cryptedData(data,packetLength);
            break;
        case IN_MESSAGE:
            receiveMessage(data,packetLength);
            break;
        case PING:
            Pong();
            break;
        case LOGIN_USERCONN:
            emit signalError(USER_ALREADY_LOGGED);
            break;
        case LOGIN_NOUSER:
            emit signalError(INVALID_USER);
            break;
        case LOGIN_ERRPASS:
            emit signalError(INVALID_PASSWORD);
            break;
        case CLIENT_EXIT_OK:
            closeConnection();
            break;
        case SEARCH_RESULT_EMAIL:
        case SEARCH_RESULT_PROFILE:
            analyzeSearchResult(data,packetLength);
            break;
        case PROFILE_REPLY:
            analyzeProfileResult(data,packetLength);
            break;
        case SEND_REPLY:
            sendReply(data,packetLength);
            break;
        case PRE_LOGON:
            selectUser(data,packetLength);
            break;
        case ROOM_LIST:
            receiveRooms(data,packetLength);
            break;
            case ROOM_NICKLIST:   // no more handled
            break;
        case MSG_FROMROOM:
            receiveMsgFromRoom(data,packetLength);
            break;
        case EXIT_FROMROOM:
        case ENTER_ROOM:
            receiveEventFromRoom(data,(SERVER_COMMAND_ID)*com,packetLength);
            break;
        case EXIT_ROOM_OK:
            SysLog("Exited from room");
            emit exitFromRoomOk();
            break;
        case GET_ROOM_PROFILE:
            break;
        case ROOM_NOTPRESENT:
            emit signalError(NONEXISTING_ROOM);
            break;
        case ROOM_CREATE_BUSY:
            emit signalError(EXISTING_ROOM);
            break;
        case SERVER_ROOMS_FOUND:
            getRoomSearchResult(data,packetLength);
            break;
        case ROOM_FULL:
            emit signalError(ROOM_ISFULL);
            break;
        case ROOM_ERROR:
            roomError(data,packetLength);    
            break;
        case CHANGE_STATUS:
            onlineStatusChange(data,packetLength);
            break;
        case SERVER_ROOM_ENTERED:
            roomEntered(data,packetLength);    
            break;   
        case SERVER_KICK_ACK:
            break;  
        case SERVER_FIND_BY_NICK:
            analyzeSearchResult(data,packetLength);         
            break;  
        case SERVER_OFFLINE_MESSAGE:
            receiveOfflineMessage(data,packetLength);    
            break;                                            
        case SERVER_KICK_BAN_ERROR:         
            receiveKickBanError(data,packetLength);    
            break;    
        default:
#ifdef C6DEBUG

            C6Logger::getInstance().debugPrint(PROTO_SIG,"Unknown command  (%0x)\n",*com);
            C6Utils::dumpPacket(PROTO_SIG,data,avail);
#endif

        }
    }
    else
    {
#ifdef C6DEBUG
        C6Logger::getInstance().debugPrint(PROTO_SIG,"Invalid server ID (%02x)\n",*com);
#endif

    }

    if (packetLength < avail - 6)    
    {
        com+=(6+packetLength-1);
        int previousPackLen = packetLength;
            
        C6Utils::safeShortRead(com+4,&packetLength,com+6);
        if (avail-previousPackLen-6 >= packetLength)                                       // just to be sure
        {         
            commandActionHandler(com,avail-previousPackLen-6);
        }         
        else
        {
#ifdef C6DEBUG
            C6Logger::getInstance().debugPrint(PROTO_SIG,"Unexpected length avail-previousPackLen-6 (%d) packL (%d)\n",avail-previousPackLen-6,packetLength);
#endif

        }
    }
}

void C6Proto::Helo(unsigned char *data,int packL)
{
    unsigned char *pbuf,*psave,*xml_blob;
    const char *nicksforuser="nicksforuser";
    QString temp_xml;

    OutCount = 1;
    temp_xml.append("<user>");
    temp_xml.append(QChar(13));
    temp_xml.append("  <username>xxyy</username>");
    temp_xml.append(QChar(13));
    temp_xml.append("  <password>zzww</password>");
    temp_xml.append(QChar(13));
    temp_xml.append("</user>");
    temp_xml.append(QChar(13));

    data+=SKIP_PACKET_HEADER;
    data+=2;

    memcpy(ServerKey,data+1,*data);
    ServerKey[*data]=0;

    orderServerKey(Ord_Key,ServerKey);
    encodeNewMd5Key(md5Key,ServerKey);

    temp_xml.replace(QString("xxyy"),firstLogin);
    temp_xml.replace(QString("zzww"),firstPassword);

   
    
    int l = ((temp_xml.length() / 8) + 1)*8;

    xml_blob = new unsigned char[l];
    memset(xml_blob,0,l);
    memcpy(xml_blob,temp_xml.latin1(),temp_xml.length());
    
    blowFishEncode(l,xml_blob,16,md5Key);

    int templen = 1+12+2+l+2;
    psave = new unsigned char[2*PACKET_HEADER_LEN+templen];
    pbuf = psave + 2*PACKET_HEADER_LEN;

    BYTE_WRITE(pbuf,0x0c);
    STR_WRITE(pbuf,nicksforuser,0x0c);
    WORD_WRITE(pbuf,l);
    STR_WRITE(pbuf,xml_blob,l);
    BYTE_WRITE(pbuf,OPENC6_CLIENT_TYPE);
    BYTE_WRITE(pbuf,OPENC6_CLIENT_VERSION);        
    
    sendToSocket(LOGIN_AUTH,psave,templen);

    delete [] xml_blob;
    delete [] psave;

    emit SysLog("HELO");
}

void C6Proto::loginAs(QString const &nick,QString const &psw)
{
    _currentLoggedNick = nick;
    _currentLoggedPassword = psw;   
    
    if (_oldAccount == false)
    {          
        retrieveStuffFromServer();
    }      
    
    login(psw);
}

void C6Proto::login(QString const &psw)
{
    int nickLength = _currentLoggedNick.length();
    unsigned char *psave = new unsigned char[2*PACKET_HEADER_LEN+43+nickLength];
    unsigned char *pbuf = psave + 2*PACKET_HEADER_LEN;
    unsigned char pwdcod[16];
    unsigned char logcod[16];   
    encodeMD5Key(psw.left(8).latin1(),ServerKey,pwdcod,true);
    encodeMD5Key(_currentLoggedNick.latin1(),ServerKey,logcod,false);

    BYTE_WRITE(pbuf,nickLength);                                      // nick len
    STR_WRITE(pbuf,_currentLoggedNick.latin1(),nickLength);           // nick
    BYTE_WRITE(pbuf,16);                                              // pwd len
    STR_WRITE(pbuf,pwdcod,16);                                        // pwd md5 coded
    BYTE_WRITE(pbuf,16);                                              // nick len
    STR_WRITE(pbuf,logcod,16);                                        // nick md5 coded
    BYTE_WRITE(pbuf,OPENC6_CLIENT_TYPE | 128);
    BYTE_WRITE(pbuf,OPENC6_CLIENT_VERSION); 
        
    unsigned int ourIP = 0;    
#if (QT_VERSION >= 0x030300)          
    ourIP = _pSocket->address().toIPv4Address();   
#else
     ourIP = _pSocket->address().ip4Addr();   
#endif   

    WORD_WRITE(pbuf,((ourIP & 0xffff0000) >> 16));                                          // localhost hi
    WORD_WRITE(pbuf,(ourIP & 0x0000ffff));
    WORD_WRITE(pbuf,0x0014);

    sendToSocket(LOGIN,psave,43+nickLength);
    delete [] psave;
}

void C6Proto::rerouteServer(unsigned char* data,int packL)
{
    int ip=0;
    int port=0;
    C6Settings &settings = C6Settings::getInstance();
    QString server;
    QString portStr;

    const unsigned char* maxPtr =  MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;

    int tmp=0;

    C6Utils::safeByteRead(data,&tmp,maxPtr);
    ip = tmp << 24;
    C6Utils::safeByteRead(data+1,&tmp,maxPtr);
    ip |= tmp << 16;
    C6Utils::safeByteRead(data+2,&tmp,maxPtr);
    ip |= tmp << 8;
    C6Utils::safeByteRead(data+3,&tmp,maxPtr);
    ip |= tmp;

    C6Utils::safeShortRead(data+6,&port,maxPtr);

    QHostAddress IP(ip);

    server = IP.toString();
    portStr = QString::number(port);

    if (settings.getProxySwitch() == true)
    {
        disconnect(_pSocket,SIGNAL(readyRead()),this,SLOT(socket_ReadyRead()) );
        disconnect(_pSocket,SIGNAL(error(int)),this,SLOT(socket_Error(int)) );
        disconnect(_pSocket,SIGNAL(bytesWritten(int)),this,SLOT(socket_bytesWritten(int)));
        disconnect(_pSocket,SIGNAL(connectionClosed ()),this,SLOT(socket_connectionClosed()));

        static_cast<C6ProxySocket*>(_pSocket)->setDestConnection(server,portStr);
        server = settings.getProxyName();
        portStr = settings.getProxyPort();
        static_cast<C6ProxySocket*>(_pSocket)->connectToHost(server,(Q_UINT16)portStr.toInt());
    }
    else
    {
        _pSocket->connectToHost(server,port);
    }

    emit SysLog("Reconnecting to "+server+" port "+portStr);
}


/** handle info login */
void C6Proto::infoLogin(unsigned char *data,int packL)
{
    const unsigned char* maxPtr = MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER-2;

    int len=0;
    C6Utils::safeShortRead(data,&len,maxPtr);             // packet len
    infoLoginFlag = true;

    if (BannerDataP != 0)
    {
        delete [] BannerDataP;
    }

    data+=2;
    BannerDataP = new unsigned char[len];
    C6Utils::safeStringCopy(BannerDataP,data,len,maxPtr);

    if (_oldAccount == true)
    {          
        emit SysLog("InfoLogin: old account mode");      
    }      
    else
    {
        emit SysLog("InfoLogin");      
    }          

    emit infoLogin(_oldAccount);  
    emit signalOnline();
    
    processInfoLogin(BannerDataP,len+BannerDataP);
    setExtendedStatus(_initStatus,_initialMessageODD);
}

void C6Proto::welcome(unsigned char *data,int packL)
{
    const unsigned char* maxPtr =  MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;

    int len = 0;
    C6Utils::safeShortRead(data,&len,maxPtr);             // packet len
    data+=2;

    unsigned char *buffer = new unsigned char[len];
    C6Utils::safeStringCopy(buffer,data,len,maxPtr);
    QString stats = QString::fromLatin1((const char*)buffer,len);
    delete [] buffer;    
    emit signalServerStats(stats);
      
}

/** notify online users  */
void C6Proto::SendUsers(unsigned char *data,int packL)
{
    int len=0;
    int status=0;
   
    C6Users::C6UsersVector usrVector;
    C6Users tmp;

    const unsigned char* maxPtr = MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;

    int nickFound=0;
    C6Utils::safeShortRead(data,&nickFound,maxPtr);
    data+=2;
    
    for(int i=0; i < nickFound; i++)
    {
        C6Utils::safeByteRead(data,&len,maxPtr);
        unsigned char* str = new unsigned char[len];
        C6Utils::safeStringCopy(str,data+1,len,maxPtr);
        QString nick = QString::fromLatin1((const char*)str,len);
        tmp.setNick(nick);
        usrVector.push_back(tmp);
        data+=len+1;
        delete [] str;
    }

    data+=2;

    for(unsigned int i=0; i < usrVector.size(); i++)
    {
        int numVariant = 0;
        QVariant variantData;            
        QString message;             
        int x = 0;    
        
        do         
        {     
            bool ok=false;        
            data+=parseAggregate(data,maxPtr,numVariant,variantData);
            int dataInt = variantData.toInt(&ok);
            
            if (ok == true)
            {                            
                status = dataInt;         
            }  
            else
            {
                message = variantData.toString();    
            }                                
                
            x++;    
                    
        } while (x < numVariant);         
              
        usrVector[i].setStatus(mapPS2US(status));
        
        if (message != QString::null)
        {
            usrVector[i].setDailyMessage(message);         
        }         
    }

    emit notifyStatus(usrVector,true);
    emit SysLog("Receiving "+QString::number(nickFound)+" online users from server");
}
/** Check the user status  */
void C6Proto::userStatus(unsigned char *data,int packL)
{
    QString tmpStr;
    C6Users::C6UsersVector usrVector;
    C6Users tmp;

    const unsigned char* maxPtr = MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;

    int len = 0;
    C6Utils::safeByteRead(data,&len,maxPtr);

    {
        unsigned char* str = new unsigned char[len];
        C6Utils::safeStringCopy(str,data+1,len,maxPtr);
        tmpStr = QString::fromLatin1((const char*)str,len);
        delete [] str;
    }

    tmp.setNick(tmpStr);

    int statusRead = 0;
    C6Utils::safeByteRead(data+1+len,&statusRead,maxPtr);

    C6Users::C6USER_STATUS status = C6Users::U_NOTPRESENT;

    if (statusRead)
    {
        status = C6Users::U_AVAILABLE;
        emit SysLog(tmpStr+" now is ONLINE");
    }
    else
    {
        status = C6Users::U_OFFLINE;
        emit SysLog(tmpStr+" now is OFFLINE");
    }

    tmp.setStatus(status);
    usrVector.push_back(tmp);

    emit notifyStatus(usrVector);
}
/** handle a chat request to a user */
void C6Proto::sendChatMessage(QString const & nick,bool status,QString &text,C6MessageStyle style)
{
    sendMessage(nick,status,text,style);
    emit SysLog("Sending message to "+nick);
}
/** Send the actual packet */
void C6Proto::sendMessage(QString const &nick,bool isOnline,QString const& text,C6MessageStyle style)
{
    int othernicklen = nick.length();
    int mynicklen = _currentLoggedNick.length();
    int textlen = text.length();
    int templen = 1+mynicklen+2+1+othernicklen+2+textlen;
    
    if (isOnline == true)
    {
        templen+=2+7;     
    }          
    
    unsigned char *psave = new unsigned char[templen+2*PACKET_HEADER_LEN];
    unsigned char *pbuf = psave + 2*PACKET_HEADER_LEN;

    BYTE_WRITE(pbuf,mynicklen);
    STR_WRITE(pbuf,_currentLoggedNick.latin1(),mynicklen);
    WORD_WRITE(pbuf,0x0001);
    BYTE_WRITE(pbuf,othernicklen);
    STR_WRITE(pbuf,nick.latin1(),othernicklen);
   
    if (isOnline == true)
    {
        WORD_WRITE(pbuf,2+textlen+7);      
        BYTE_WRITE(pbuf,style.getMessageType());
        BYTE_WRITE(pbuf,style.getOperationType());
       
        int red;
        int green;
        int blue;
               
        style.getRGB(red,green,blue);    
    
        STR_WRITE(pbuf,text.latin1(),textlen);
        BYTE_WRITE(pbuf,0);
        BYTE_WRITE(pbuf,style.getFontStyle());    
        BYTE_WRITE(pbuf,red);
        BYTE_WRITE(pbuf,green);
        BYTE_WRITE(pbuf,blue);         
        BYTE_WRITE(pbuf,style.getFontTypeNo());
        BYTE_WRITE(pbuf,style.getFontSizePt()); 
        
        sendToSocket(OL_MESSAGE,psave,templen);      
    }
    else
    {
        WORD_WRITE(pbuf,textlen); 
        STR_WRITE(pbuf,text.latin1(),textlen);              
        sendToSocket(OF_MESSAGE,psave,templen);      
    }          
    delete [] psave;
}
/** handle an incoming crypted message */
void C6Proto::cryptedData(unsigned char *data,int packL)
{
    const unsigned char* maxPtr =  MAX_PTR(packL);
    int len; 
    C6Utils::safeShortRead(data+4,&len,maxPtr);    
    data+=SKIP_PACKET_HEADER;   
    unsigned char* in_buf = new unsigned char[len];
    xorCode(data,in_buf,Ord_Key,len);
    commandActionHandler(in_buf,len);
    delete [] in_buf;
}


void C6Proto::receiveMessage(unsigned char *data,int packL)
{
    const unsigned char* maxPtr =  MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;
    
    unsigned char nickfromlen =0;    
    C6Utils::safeByteRead(data,&nickfromlen,maxPtr);
    unsigned char* nickfrom = new unsigned char[nickfromlen];
    C6Utils::safeStringCopy(nickfrom,data+1,nickfromlen,maxPtr);
    QString nickfromstr = QString::fromLatin1((const char*)nickfrom,nickfromlen);
    
    delete [] nickfrom;
    
    int messlen = 0;   
    data+=(1+nickfromlen);
    data+=(*data)+1;
    C6Utils::safeShortRead(data,&messlen,maxPtr);
    data+=2;                    // skip dest it's me
    messlen-=2;

    unsigned char messageType = 0;
    unsigned char operationType = 0;
    C6Utils::safeByteRead(data,&messageType,maxPtr);
    data++;
    C6Utils::safeByteRead(data,&operationType,maxPtr);
    data++;
    
    QString messagestr;    
    
    if (messageType == NEW_STYLE_MSG)
    {  
        messagestr = QString::fromLatin1((const char*)data);      
        data+=messagestr.length();        
                  
        C6MessageStyle msg;      
        unsigned char tmp;    
        
        if (C6Utils::safeByteRead(data,&tmp,maxPtr))     // zero 
        {
            unsigned char fontStyle;    
            C6Utils::safeByteRead(data+1,&fontStyle,maxPtr);    
            msg.setFontStyle(fontStyle);    
                
            unsigned char red;
            unsigned char green;
            unsigned char blue;          
            
            C6Utils::safeByteRead(data+2,&red,maxPtr);
            C6Utils::safeByteRead(data+3,&green,maxPtr);
            C6Utils::safeByteRead(data+4,&blue,maxPtr);          
            msg.setRGB(red,green,blue);      
            
            unsigned char fontNo;   
            C6Utils::safeByteRead(data+5,&fontNo,maxPtr);          
            msg.setFontTypeNo(fontNo);      
            unsigned char fontSize;    
            C6Utils::safeByteRead(data+6,&fontSize,maxPtr); 
            msg.setFontSizePt(fontSize);
        }   
        
        emit messageReceived(nickfromstr,messagestr,&msg);      
        emit SysLog("Receving new style message from "+nickfromstr);             
    }
    else
    {          
        messagestr = QString::fromLatin1((const char*)data,messlen);
              
        if (messageType == SELF)
        {
            switch (operationType)
            {
            case REQUEST_FILE_ACCEPT:
                emit messageReceived(nickfromstr,messagestr);         
                getIPAddress(sendNick);
                emit SysLog("Trying to send a file to "+nickfromstr);
                break;
                
            case REQUEST_FILE:
                emit prepareFileReception(nickfromstr,messagestr);
                emit SysLog(nickfromstr+" is trying to send a file");
                break;        
                
            case AUTH_BUDDY_OP:
                {
                    QString logMsg;
                        
                    if (_configurationMode == C6XCAPClient::WARN)
                    {
                        messagestr = WARN_ACCEPT_STR;    
                        logMsg = " has added you to contact list";    
                    }                
                    else
                    {            
                        messagestr = AUTH_ACCEPT_STR;
                        logMsg = " is asking for authorization";    
                    }            
                    
                    emit SysLog(nickfromstr+logMsg);   
                    emit messageReceived(nickfromstr,messagestr);                
                }     
                break;                
                case FILE_TRANSFER_AUDIO_VIDEO:
                    break;              
                case FILE_TRANSFER_OP:
                    break;            
            default:
                emit messageReceived(nickfromstr,messagestr);         
                break;
            }
        }
        else
        {
            emit messageReceived(nickfromstr,messagestr);      
            emit SysLog("Receving plain message from "+nickfromstr);
        }
    }
}

void C6Proto::socket_connectionClosed()
{
    emit SysLog("Connection was closed from server");

    if (infoLoginFlag)                                    // socket already connected
    {
        emit SignalOffline(true);
        emit SysLog("Status Offline");
    }
}

/** answer pong to server pings */
void C6Proto::Pong()
{
    unsigned char *savebuf = new unsigned char[2*PACKET_HEADER_LEN];
    sendToSocket(PONG,savebuf,0);

    delete [] savebuf;
    emit SysLog("PING - PONG ");
}

/** exit c6 server  */
void C6Proto::ReqClientExit()
{
    unsigned char *links=0,*tocryp=0,*save=0;
    unsigned char *BannerData=BannerDataP;
    unsigned char numbanners;
    int cryplen;
    int old_len = 0;

    if (infoLoginFlag)                                                   /* already connected */
    {
        numbanners = *BannerData++;

        for( int i=0; i < numbanners; i++)
        {
            int banlen;

            BannerData+=(*BannerData)+1;
            banlen = (*BannerData)+1;

            if (old_len)
            {
                links = (unsigned char*)new unsigned char [old_len+banlen+6];
                memcpy(links,save,old_len);
                delete [] save;
            }
            else
            {
                links = (unsigned char*) new unsigned char[banlen+6];
                save = links;
            }

            memcpy(links+old_len,BannerData,banlen);
            memset(links+old_len+banlen,0,6);
            old_len += (banlen+6);
            save = links;

            BannerData+=(*BannerData)+1;
            BannerData+=(*BannerData)+1;
        }

        cryplen = 1 + _currentLoggedNick.length() + 1 + old_len;

        links = new unsigned char [cryplen+2*PACKET_HEADER_LEN];
        tocryp = links + 2*PACKET_HEADER_LEN;

        BYTE_WRITE(tocryp,_currentLoggedNick.length());
        STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());
        BYTE_WRITE(tocryp,numbanners);
        STR_WRITE(tocryp,save,old_len);

        sendToSocket(CLIENT_REQ_EXIT,links,cryplen);

        delete [] links;
        delete [] save;

        emit SysLog("Request client exit");
    }
    else
    {
        closeSocket();
        emit SysLog("Brute force request client exit");
    }
}
/** remove a user from c6 server list  */
void C6Proto::RemoveUser(QString nick)
{
    int len = 3+nick.length();

    unsigned char *psave = new unsigned char[len+2*PACKET_HEADER_LEN];
    unsigned char *tocryp = psave + 2*PACKET_HEADER_LEN;

    WORD_WRITE(tocryp,1);
    BYTE_WRITE(tocryp,nick.length());
    STR_WRITE(tocryp,nick.latin1(),nick.length());

    sendToSocket(DEL_USERS,psave,len);

    delete [] psave;
    emit SysLog("Remove "+nick+" from server notify list");
}

/** extract profile link and register link */
void C6Proto::processInfoLogin(unsigned char* data,const unsigned char* maxPtr)
{
    unsigned char *bannerData=data;

    int capab = 0;    
    int capabLo = 0;    
    
    C6Utils::safeShortRead(data,&capab,maxPtr);    
    capab<<=8;    
    C6Utils::safeShortRead(data+2,&capabLo,maxPtr);    
    capab |= capabLo;    
    
    _hasNAT = (capab & SERVER_CLIENTISNAT) != 0;    
    
    bannerData+=4; // skip server capabilities
    
    int numAdv = 0;
    C6Utils::safeByteRead(bannerData,&numAdv,maxPtr);

    for (int i=0; i < numAdv; i++)
    {
        int advLen = 0;
        bannerData++;
        C6Utils::safeByteRead(bannerData,&advLen,maxPtr);
        bannerData+=(advLen+1);
        C6Utils::safeByteRead(bannerData,&advLen,maxPtr);
        bannerData+=(advLen+1);
        C6Utils::safeByteRead(bannerData,&advLen,maxPtr);
        bannerData+=(advLen+1);
    }

    bannerData+=2;

    int numbanners = 0;
    C6Utils::safeByteRead(bannerData,&numbanners,maxPtr);
    bannerData++;

    char url[256];

    for( int i=0; i < numbanners; i++)
    {
        int banNoLen = 0;
        C6Utils::safeByteRead(bannerData,&banNoLen,maxPtr);
        bannerData++;

        char banNoStr[10];

        for (int j=0; j < banNoLen; j++)
        {
            C6Utils::safeByteRead(bannerData,reinterpret_cast<unsigned char*>(&banNoStr[j]),maxPtr);
            bannerData++;
        }

        banNoStr[banNoLen] = 0;
        int banLen = 0;
        C6Utils::safeByteRead(bannerData,&banLen,maxPtr);

        C6Utils::safeStringCopy(reinterpret_cast<unsigned char*>(url),bannerData+1,banLen,maxPtr);
        url[banLen]=0;
        _buttonURL["BUT"+QString(const_cast<char*>(banNoStr))]=QString(const_cast<char*>(url));

        bannerData+=(1+banLen);
        C6Utils::safeByteRead(bannerData,&banLen,maxPtr);
        bannerData+=(1+banLen);
      //  qWarning("BUT %s %s\n",banNoStr,url);
    }
    
    processButtons();    
}
/** actually send data to socket  */
void C6Proto::sendToSocket(CLIENT_COMMAND_ID command,unsigned char *buf,int len)
{
    unsigned char *buftosend = buf;

    WORD_WRITE(buftosend,CLIENTID);
    WORD_WRITE(buftosend,OutCount);
    WORD_WRITE(buftosend,len+PACKET_HEADER_LEN);
    WORD_WRITE(buftosend,command);
    WORD_WRITE(buftosend,OutCount);
    WORD_WRITE(buftosend,len);

    xorCode(buf+PACKET_HEADER_LEN,buf+PACKET_HEADER_LEN,Ord_Key,len+PACKET_HEADER_LEN);

#ifdef C6DEBUG

    C6Logger::getInstance().debugPrint(PROTO_SIG,"%d bytes sent to socket %s for command ID 0x%02x\n",len+PACKET_HEADER_LEN*2,
                                       _pSocket->peerName().latin1(),command);
#endif

    if ((_pSocket != 0) && (_pSocket->state() == QSocket::Connected))
    {
        _pSocket->writeBlock((char*)buf,len+PACKET_HEADER_LEN*2);
        _pSocket->flush();
        OutCount++;
    }
}

/** terminate a connection and signal the client */
void C6Proto::closeConnection()
{
    emit SysLog("Client exited normally and now status is offline");
    emit SignalOffline(false);
}

/** close a socket connection */
void C6Proto::closeSocket()
{
    if (_pSocket != 0)
    {
        _pSocket->close();

        while (_pSocket->state() == QSocket::Closing)
        {}
    }
}

void C6Proto::sendUserRequest(QStringList & nick_lst)
{
    unsigned char *pbuf,*psave;
    QString line;
    int cl;
    int len;

    int totcount = 0;
    int loccount=0;
    int numnick = nick_lst.count();

    if (numnick)
    {
        psave = new unsigned char[MAXNICKBLOB*(MAXNICKLEN+1)+2+PACKET_HEADER_LEN*2];

        while (totcount < numnick)
        {
            pbuf = psave + PACKET_HEADER_LEN*2+2;
            cl = 0;

            for (loccount=0; (loccount < MAXNICKBLOB) && (totcount < numnick); loccount++,totcount++)
            {
                len = nick_lst[totcount].length();
                cl+=(len+1);

                BYTE_WRITE(pbuf,len);
                STR_WRITE(pbuf,nick_lst[totcount].latin1(),len);
            }

            cl+=2;

            pbuf = psave + PACKET_HEADER_LEN*2;
            WORD_WRITE(pbuf,loccount);

            sendToSocket(REQ_USERS,psave,cl);
            emit SysLog("Sent user request list for "+ QString::number(loccount) +" nicks");
        }
        delete [] psave;
    }
    else
    {
        if (_socketStatusProgress <=100)
        {
            _socketStatusProgress=101;
            emit progress(_socketStatusProgress);
        }
    }
}

void C6Proto::sendUserRequest(QString const &nick)
{
    int len = nick.length();

    unsigned char *psave = new unsigned char[(len+1)+2+PACKET_HEADER_LEN*2];
    unsigned char *pbuf = psave + PACKET_HEADER_LEN*2;

    WORD_WRITE(pbuf,1);
    BYTE_WRITE(pbuf,len);
    STR_WRITE(pbuf,nick.latin1(),len);
    sendToSocket(REQ_USERS,psave,len+1+2);

    delete [] psave;

    emit SysLog("Sent User request for nick "+nick);
}


void C6Proto::socket_bytesWritten(int bytes)
{
    while(_pSocket->bytesToWrite())
    {}
}

void C6Proto::sendSearch(unsigned char *seq,C6Proto::USER_SEARCH_TYPE type)
{
    int count = seq[0];
    unsigned char *savebuf = new unsigned char[count*2+2+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;

    switch(type)
    {
        case EMAIL_SEARCH:
            BYTE_WRITE(tocryp,count);
            STR_WRITE(tocryp,&seq[1],count);
            sendToSocket(SEARCHEMAIL,savebuf,count+1);
            break;          
        case PROFILE_SEARCH:
            WORD_WRITE(tocryp,count);
            STR_WRITE(tocryp,&seq[1],count*2);
            sendToSocket(SEARCHPROFILE,savebuf,count*2+2);
            break;            
        case NICK_SEARCH:
           
            break;            
    }          

    delete [] savebuf;
    emit SysLog("Search Started");
}

void C6Proto::searchByNick(QString const& nick)
{
    int len = 1+_currentLoggedNick.length()+1+nick.length();
    unsigned char *savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;
       
    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length()); 
    BYTE_WRITE(tocryp,nick.length());
    STR_WRITE(tocryp,nick.latin1(),nick.length()); 
                             
    sendToSocket(CLIENT_FIND_NICK,savebuf,len);  
    
    delete [] savebuf;
    emit SysLog("Search for users matching nick "+nick+"+started");     
}      

void C6Proto::analyzeSearchResult(unsigned char *data,int packL)
{
    QStringList strlst;

    const unsigned char* maxPtr =  MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;
    
    int count = 0;
    C6Utils::safeShortRead(data,&count,maxPtr);
    data+=2;

    std::vector<C6Users::C6USER_STATUS> statusLst;

    for(int i=0; i < count; i++)
    {
        int len = 0;
        C6Utils::safeByteRead(data,&len,maxPtr);
        {
            unsigned char* tmpnick = new unsigned char[len];
            C6Utils::safeStringCopy(tmpnick,data+1,len,maxPtr);
            strlst+=QString::fromLatin1((const char*)tmpnick,len);
            data+=1+len;
            unsigned char sts = 0;
            C6Utils::safeByteRead(data,&sts,maxPtr);
            statusLst.push_back(mapPS2US(sts));
            data++;
            delete [] tmpnick;
        }
    }

    if (data < maxPtr)      // extended status present
    {
        statusLst.clear();
        for(int i=0; i < count; i++)
        {
            QVariant variantData;
            int numVariant = 0;    
            int x = 0;    
            
            do         
            {     
                bool ok=false;        
                data+=parseAggregate(data,maxPtr,numVariant,variantData);
                int dataInt = variantData.toInt(&ok);
                
                if (ok == true)
                {                            
                    statusLst.push_back(mapPS2US(dataInt));        
                }               
                
                x++;    
                    
            } while (x < numVariant);            
        }
    }

    emit notifySearchList(&strlst,statusLst);
    emit SysLog("Search found "+QString::number(count)+" matching netfriends");
}

void C6Proto::requestProfile(const QString & nick)
{
    profileRequestDB.push_back(nick);
    requestInfo(nick);
}

void C6Proto::requestInfo(QString const &nick)
{
    int len = nick.length();

    unsigned char *savebuf = new unsigned char[len+1+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;

    BYTE_WRITE(tocryp,len);
    STR_WRITE(tocryp,nick.latin1(),len);
    sendToSocket(REQ_PROFILE,savebuf,len+1);

    delete [] savebuf;
    emit SysLog("Request profile for "+nick);
}

void C6Proto::analyzeProfileResult(unsigned char *data,int packL)
{
    bool foundReq = false;
    const unsigned char* maxPtr =  MAX_PTR(packL);

    data+=SKIP_PACKET_HEADER;

    unsigned char nicklen = 0;
    C6Utils::safeByteRead(data,&nicklen,maxPtr);
    QString nick = QString::fromLatin1((const char*)data+1,nicklen);

    for (unsigned int i=0; i < profileRequestDB.size(); i++)
    {
        if (profileRequestDB.at(i).compare(nick) == 0)
        {
            profileRequestDB.erase(profileRequestDB.begin() + i);
            foundReq = true;
            break;
        }
    }

    emit notifyInfoResult(nick,data,packL,foundReq);
}

void C6Proto::getIPAddress(QString const &nick)
{
    int len = 1+_currentLoggedNick.length()+1+nick.length()+1;
    unsigned char *psave = new unsigned char[len+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = psave + PACKET_HEADER_LEN*2;

    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());
    BYTE_WRITE(tocryp,nick.length());
    STR_WRITE(tocryp,nick.latin1(),nick.length());
    BYTE_WRITE(tocryp,FILE_TRANSFER_OP);

    sendToSocket(GET_IPADRESS,psave,len);

    delete [] psave;

    emit SysLog("Requesting IP address of "+nick);
}

void C6Proto::sendReply(unsigned char *data,int packL)
{
    int ip,port;
    unsigned char ip_buf[4];
    QString nick_ip;

    const unsigned char* maxPtr =  MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;

    int tmp = 0;
    C6Utils::safeByteRead(data,&tmp,maxPtr);
    data+=tmp+1;        // pos on IP

    C6Utils::safeByteRead(data,&tmp,maxPtr);
    ip_buf[0]=tmp^ServerKey[7];
    C6Utils::safeByteRead(data+1,&tmp,maxPtr);
    ip_buf[1]=tmp^ServerKey[5];
    C6Utils::safeByteRead(data+2,&tmp,maxPtr);
    ip_buf[2]=tmp^ServerKey[6];
    C6Utils::safeByteRead(data+3,&tmp,maxPtr);
    ip_buf[3]=tmp^ServerKey[1];

    ip = (((int)ip_buf[0]) << 24) | ((int)(ip_buf[1]) << 16) | (((int)ip_buf[2]) << 8) | (((int)ip_buf[3]));
    C6Utils::safeShortRead(data+6,&port,maxPtr);

    QHostAddress IP(ip);
    nick_ip = IP.toString();
    
    if (port)
    {
        emit SysLog("Prepare sending file to "+IP.toString()+":"+QString::number(port));
        emit fireConnection(IP,port,sendFilePath,sendNick);
    }
    else
    {
        emit signalError(XFERFAIL);
        emit SysLog("Receiving file is not allowed for remote user");
    }
}

void C6Proto::grantIP(const QString &ip,int port,const QString &nickToGrant)
{
    QString nick = nickToGrant;   
    int len = 1+_currentLoggedNick.length()+1+nick.length()+2+2+1+4;
    unsigned char *savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;
     
    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());
    BYTE_WRITE(tocryp,nick.length());
    STR_WRITE(tocryp,nick.latin1(),nick.length());
    WORD_WRITE(tocryp,0);
        
    WORD_WRITE(tocryp,port);
    BYTE_WRITE(tocryp,FILE_TRANSFER_OP);
   
    char iphex[4];
    iphex[0]= ip.section('.',0,0).toInt();
    iphex[1]= ip.section('.',1,1).toInt();       
    iphex[2]= ip.section('.',2,2).toInt();    
    iphex[3]= ip.section('.',3,3).toInt();
    
    BYTE_WRITE(tocryp,iphex[0]);
    BYTE_WRITE(tocryp,iphex[1]);
    BYTE_WRITE(tocryp,iphex[2]);
    BYTE_WRITE(tocryp,iphex[3]);
    
    sendToSocket(GRANT_IP,savebuf,len);

    delete [] savebuf;
    emit SysLog("Gateway "+ip+" on port "+QString::number(port));     
}      

int C6Proto::activateFileReception(QString const& nick,int port)
{
    int len = 1+_currentLoggedNick.length()+1+nick.length()+2+2+1;

    unsigned char *savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;
    
    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());
    BYTE_WRITE(tocryp,nick.length());
    STR_WRITE(tocryp,nick.latin1(),nick.length());
    WORD_WRITE(tocryp,0);
    WORD_WRITE(tocryp,port);
    BYTE_WRITE(tocryp,FILE_TRANSFER_OP);

    sendToSocket(GRANT_IP,savebuf,len);

    delete [] savebuf;
    emit SysLog("Activated file server on port "+QString::number(port)+" to grant "+nick);
}

void C6Proto::getGateway(QString &ip,int &port)
{
    static int i=0;    
    
    if (_gatewayList->count() > 0)
    {         
        ip = (*_gatewayList)[i % 3];
        i++;           
    }      
    port = 9999;        
}

/*!
    \fn C6Proto::requestCategoryList()
 */
void C6Proto::requestCategoryList()
{
    unsigned char *tocryp,*savebuf;
    int len = 1+_currentLoggedNick.length();

    savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    tocryp = savebuf + PACKET_HEADER_LEN*2;

    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());

    sendToSocket(QUERY_ROOM,savebuf,len);

    delete [] savebuf;
    emit SysLog("Query for chat rooms");
}



/*!
    \fn C6Proto::receiveRooms()
 */
void C6Proto::receiveRooms(unsigned char *data,int packL)
{
    int rooms_no=0;
    int people_no=0;
    int len=0;
    QString name;

    const unsigned char* maxPtr =  MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;

    data+=2;
    C6Utils::safeShortRead(data,&rooms_no,maxPtr);
    data+=2;

    for (int i=0; i < rooms_no; i++)
    {
        C6Utils::safeByteRead(data,&len,maxPtr);
        data++;
        unsigned char* str = new unsigned char[len];
        C6Utils::safeStringCopy(str, data,len,maxPtr);
        name = QString::fromLatin1((const char*)str,len);
        data+=len;
        C6Utils::safeShortRead(data,&people_no,maxPtr);
        data+=2;

        unsigned char kind;
        C6Utils::safeByteRead(data,&kind,maxPtr);
        data+=3;
        emit updateRooms(name,people_no,kind);
        delete [] str;
    }

    emit SysLog("Received "+QString::number(rooms_no)+" rooms");

}

/*!
    \fn C6Proto::sendMessageToRoom(QString msg,int style )
 */
void C6Proto::sendMessageToRoom(QString &name,QString &msg,int style)
{
    unsigned char *tocryp,*savebuf;
    QString room_name = name;
    QString mess = msg;

    int len = 1+_currentLoggedNick.length()+1+room_name.length()+4+mess.length();

    savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    tocryp = savebuf + PACKET_HEADER_LEN*2;

    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());
    BYTE_WRITE(tocryp,room_name.length());
    STR_WRITE(tocryp,room_name.latin1(),room_name.length());
    WORD_WRITE(tocryp,mess.length()+2);
    WORD_WRITE(tocryp,0);
    STR_WRITE(tocryp,mess.latin1(),mess.length());

    sendToSocket(ROOM_MSG,savebuf,len);

    delete [] savebuf;
    emit SysLog("Sent message to room "+room_name);
}


/*!
    \fn C6Proto::receiveMsgFromRoom(unsigned char *data)
 */
void C6Proto::receiveMsgFromRoom(unsigned char *data,int packL)
{
    const unsigned char* maxPtr = MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;
    
    QString nickfrom;   
    int len;   
    C6Utils::safeByteRead(data,&len,maxPtr);
    data++;
    {
        unsigned char *str = new unsigned char[len];
        C6Utils::safeStringCopy(str,data,len,maxPtr);
        nickfrom = QString::fromLatin1((const char*)str,len);
        delete [] str;
    }

    data+=len;
    
    QString roomName;
   
    C6Utils::safeByteRead(data,&len,maxPtr);
    data++;
    {
        unsigned char *str = new  unsigned char[len];
        C6Utils::safeStringCopy(str,data,len,maxPtr);
        roomName = QString::fromLatin1((const char*)str,len);
        delete [] str;
    }
    data+=len;
    
    C6Utils::safeByteRead(data,&len,maxPtr);
    data+=(len+1);                       // skip nick dest
    
    int type;    
    C6Utils::safeByteRead(data,&type,maxPtr);
    data++;    
    
    int messageLen;    
    C6Utils::safeShortRead(data,&messageLen,maxPtr);
    data+=2;
    
    int messageType;    
    C6Utils::safeByteRead(data,&messageType,maxPtr);
    data++;
    int operationType;   
    C6Utils::safeByteRead(data,&operationType,maxPtr);
    data++;   
    
    QString msg;
    
    {
        unsigned char *str = new  unsigned char[messageLen-2];
        C6Utils::safeStringCopy(str,data,messageLen-2,maxPtr);
        msg = QString::fromLatin1((const char*)str,messageLen-2);
        delete [] str;
    }    
    
    if (operationType == MODERATED || operationType == SCREENED)
    {
        nickfrom = msg.section("~",1,1);
        msg = msg.section("~",-1,-1);        
    }          
    
    emit messageFromRoom(roomName,nickfrom,msg);
    emit SysLog("Received message from "+nickfrom+" for room "+roomName);
}



/*!
    \fn C6Proto::receiveExitFromRoom(unsigned char *data)
 */
void C6Proto::receiveEventFromRoom(unsigned char *data,SERVER_COMMAND_ID action,int packL)
{
    unsigned char len=0;
    QString nick,room_name;

    const unsigned char* maxPtr = MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;

    C6Utils::safeByteRead(data,&len,maxPtr);
    data++;
    {
        unsigned char *str = new  unsigned char[len];
        C6Utils::safeStringCopy(str,data,len,maxPtr);
        nick = QString::fromLatin1((const char*)str,len);
        delete [] str;
    }
    data+=len;
    C6Utils::safeByteRead(data,&len,maxPtr);
    data++;
    {
        unsigned char *str = new  unsigned char[len];
        C6Utils::safeStringCopy(str,data,len,maxPtr);
        room_name = QString::fromLatin1((const char*)str,len);
        delete [] str;
    }

    emit eventFromRoom(room_name,nick,action);

    if (action == EXIT_FROMROOM)
    {
        emit SysLog("User "+nick+" exited from room "+room_name);
    }
    else
    {
        emit SysLog("User "+nick+" entered in room "+room_name);
    }
}


/*!
    \fn C6Proto::exitFromRoom(QString const& room)
 */
void C6Proto::exitFromRoom(QString const& room)
{
    int len = 1+_currentLoggedNick.length()+1+room.length() + 1;

    unsigned char *savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;
    
    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());
    BYTE_WRITE(tocryp,room.length());
    STR_WRITE(tocryp,room.latin1(),room.length());
    BYTE_WRITE(tocryp,0);
    sendToSocket(CLIENT_EXIT_ROOM,savebuf,len);

    delete [] savebuf;
    emit SysLog("Request for exiting from room "+room);
}

/*!
    \fn C6Proto::createRoom(QString const& roomName, QString const& topic,int roomAttribute,int index,int enterMode,QString const & password)
 */
void C6Proto::createRoom(QString const& roomName, QString const& topic,int roomAttribute,int index,int enterMode,QString const& password)
{
    static const int BASE_ID = 50;
    int propertyNo = categoryVector[index].subid.size();
    
    int passwordLen = 0;
    
    if (password.length() > 0)
    {
        passwordLen = password.length();
    }        

    int len = 1+_currentLoggedNick.length()+1+roomName.length()
            +2+topic.length()+4+1+passwordLen+4+2+propertyNo*2;
        

    unsigned char* savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    unsigned char* tocryp = savebuf + PACKET_HEADER_LEN*2;

    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());
    BYTE_WRITE(tocryp,roomName.length());
    STR_WRITE(tocryp,roomName.latin1(),roomName.length());
    WORD_WRITE(tocryp,topic.length());
    STR_WRITE(tocryp,topic.latin1(),topic.length());
    WORD_WRITE(tocryp,(roomAttribute >> 16) & 0xffff);
    WORD_WRITE(tocryp,(roomAttribute & 0xffff));
    BYTE_WRITE(tocryp,passwordLen);
    if (password.length() > 0)
    {
        STR_WRITE(tocryp,password.latin1(),passwordLen);      
    }        
    WORD_WRITE(tocryp,(enterMode >> 16));
    WORD_WRITE(tocryp,(enterMode & 0xffff));   
    WORD_WRITE(tocryp,propertyNo);

    for (int i = 0; i < propertyNo; i++)
    {         
        BYTE_WRITE(tocryp,BASE_ID+i);
        BYTE_WRITE(tocryp,categoryVector[index].subid[i]);       
    }         

    sendToSocket(CLIENT_CREATE_ROOM,savebuf,len);

    delete [] savebuf;
    emit SysLog("Request room creation of "+roomName);
}


/*!
    \fn C6Proto::roomSearch(QString const& room_name,int roomAttribute,unsigned char *property)
 */
void C6Proto::roomSearch(int roomAttribute,unsigned char *property,QString roomName)
{
    int len = 1+_currentLoggedNick.length()+1+roomName.length()+4+2+property[0]*2+4;

    unsigned char *savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;

    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());

    BYTE_WRITE(tocryp,roomName.length());
    STR_WRITE(tocryp,roomName.latin1(),roomName.length());
    
    WORD_WRITE(tocryp,(roomAttribute >> 16) & 0xffff);
    WORD_WRITE(tocryp,(roomAttribute & 0xffff));    
    
    WORD_WRITE(tocryp,property[0]);
    STR_WRITE(tocryp,&property[1],property[0]*2);
    
    WORD_WRITE(tocryp,0);
    WORD_WRITE(tocryp,0);   
    
    sendToSocket(CLIENT_SEARCH_ROOM,savebuf,len);

    delete [] savebuf;
    emit SysLog("Request for room search");
}


/*!
    \fn C6Proto::getRoomSearchResult(unsigned char *data)
    get results from room search
 */
void C6Proto::getRoomSearchResult(unsigned char *data,int packL)
{
    const unsigned char* maxPtr = MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;

    int roomsFound;    
    C6Utils::safeIntRead(data,&roomsFound,maxPtr);
    data+=4;    
    
    std::vector<RoomSearchResult> result;    
    for (int i=0; i < roomsFound; i++)
    {
        RoomSearchResult searchItem;    
        int len;    
        C6Utils::safeByteRead(data,&len,maxPtr);
        data++; 
        {
            unsigned char* temp = new unsigned char[len];
            C6Utils::safeStringCopy(temp,data,len,maxPtr);
            searchItem.roomName = QString::fromLatin1((const char*)temp,len);
            delete [] temp;  
        }
        data+=len;            
          
        int roomUsersCount;
        C6Utils::safeShortRead(data,&roomUsersCount,maxPtr);        
        data+=2;     
        searchItem.roomUsersCount = roomUsersCount;
        
        int roomAttribute;
        C6Utils::safeIntRead(data,&roomAttribute,maxPtr);        
        data+=4;
        searchItem.roomAttribute = roomAttribute;    
        
        int profileFields;
        C6Utils::safeShortRead(data,&profileFields,maxPtr);               
        data+=2;
        searchItem.profileFields = profileFields;    
        
        for (int j=0; j < profileFields; j++)
        {
            unsigned char value;
                    
            C6Utils::safeByteRead(data,&value,maxPtr);            
            data++;
            searchItem.subid.push_back(value);
            C6Utils::safeByteRead(data,&value,maxPtr);            
            data++;
            searchItem.subid.push_back(value); 
        }   
        
        int userRole;
        C6Utils::safeIntRead(data,&userRole,maxPtr);            
        data+=4;           
        result.push_back(searchItem);      
    }          
    
   emit searchResultReady(result);
   emit SysLog("Found "+QString::number(roomsFound)+" rooms");
}

void C6Proto::proxyConnected()
{
    socket_Connected();
    connect(_pSocket,SIGNAL(readyRead()),SLOT(socket_ReadyRead()));
    connect(_pSocket,SIGNAL(bytesWritten(int)),SLOT(socket_bytesWritten(int)));
}

void C6Proto::proxyError(int error)
{
    int proxyError = 0;

    switch(error)
    {
    case C6ProxySocket::METHOD_ERROR:
        proxyError = PROXY_METHOD_ERROR;
        break;
    case C6ProxySocket::BAD_ANSWER:
        proxyError = PROXY_BAD_ANSWER;
        break;
    case C6ProxySocket::BAD_AUTH:
        proxyError = PROXY_BAD_AUTH;
        break;
    }

    emit signalError(proxyError);
}


/*!
    \fn C6Proto::onlineStatusChange(unsigned char* data,int packL)
 */
void C6Proto::onlineStatusChange(unsigned char* data,int packL)
{
    const unsigned char* maxPtr =  MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;

    int len = 0;
    C6Utils::safeByteRead(data,&len,maxPtr);
    data++;

    unsigned char *temp = new unsigned char[len];
    C6Utils::safeStringCopy(temp,data,len,maxPtr);
    QString nick = QString::fromLatin1((const char*)temp,len);

    data+=len;

    data++; // unknown
    int newStatus = FREE;

    QVariant variantData;
    int numVariant = 0;        
    int x = 0;
    QString message;   
    
    do         
    {     
        bool ok=false;        
        data+=parseAggregate(data,maxPtr,numVariant,variantData);
        int dataInt = variantData.toInt(&ok);
                
        if (ok == true)
        {
            newStatus = dataInt;        
        }
        else
        {
            message = variantData.toString();    
        }                     
                
        x++;    
                    
    } while (x < numVariant);      
    
    C6Users::C6Users tmpUser("",nick,message,mapPS2US(newStatus));     
    emit extendedChangeStatus(tmpUser);

    delete [] temp;
}

void C6Proto::setExtendedStatus(C6Users::C6USER_STATUS status,QString const& message,bool reloadAuthList)
{
    QString newOwnMessage = message;
  
    if (newOwnMessage == QString::null) 
    {
        newOwnMessage =_previousOwnMessage;
    }
    
    if ((status != _previousStatus) || (newOwnMessage.compare(_previousOwnMessage) != 0) || reloadAuthList)
    {
        int mappedStatus = mapUS2PS(status);

        if (_ipVisible)
        {
            mappedStatus |= IP_VISIBLE;
        }

        mappedStatus |= FILE_TRANSFER;

        if (status == C6Users::U_AWAY)
        {
            int mappedOldStatus = mapUS2PS(_previousStatus);
            mappedStatus |= mappedOldStatus;
        }    
        
        std::vector<char> data;    
        int counter = 0;
        QVariant variant = mappedStatus;    
        
        writeAggregate(data,2,counter,variant);
            
        variant = newOwnMessage; 
        writeAggregate(data,2,counter,variant);
            
        char* tmp = new char[data.size()];        
        
        for (unsigned int i=0; i < data.size(); i++)
        {
            tmp[i] = data[i];
        }             
        
        int len = 1 + _currentLoggedNick.length() + data.size() + 4;

        unsigned char *savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
        unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;

        BYTE_WRITE(tocryp,_currentLoggedNick.length());
        STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());    
        
        STR_WRITE(tocryp,tmp,data.size());    
        
        WORD_WRITE(tocryp,0);
            
        int authYes = 0;
            
        if (reloadAuthList == true)
        {
            authYes = 1;         
        }             
        
        WORD_WRITE(tocryp,authYes);

        sendToSocket(EXTENDED_STATUS,savebuf,len);
        _previousStatus = status;
        _previousOwnMessage = newOwnMessage;      

        delete [] tmp;    
        delete [] savebuf;
        emit SysLog("setExtentedStatus");
    }
}

void C6Proto::changeStatus(C6Users::C6USER_STATUS status,QString const &message,bool reloadAuthList)
{
    setExtendedStatus(status,message,reloadAuthList);
}

void C6Proto::setInitialStatus(C6Users::C6USER_STATUS status,bool ipVisible)
{
    _initStatus = status;
    _ipVisible = ipVisible;
}

void C6Proto::setMessageOfTheDay(QString const & message)
{
    if ((message == QString::null) || (message.compare("none") == 0))    
    {
        _initialMessageODD = "";      
    }
    else
    {      
        _initialMessageODD = message; 
    }      
}

/*!
    \fn C6Proto::selectUser()
 */
void C6Proto::selectUser(unsigned char *data,int packL)
{
    int len=0;

    const unsigned char* maxPtr =  MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;
    C6Utils::safeShortRead(data,&len,maxPtr);

    if (len > 0)
    {
        blowFishDecode(len,data+2,16,md5Key);
        emit nowSelectUser(data+2);
        emit SysLog("selectUserID");
    }
    else
    {
        emit signalError(INVALID_NAME);
    }
}

void C6Proto::getCategoryFromHttp()
{
    httpCategoryFetch= new C6HttpConnection(getButtonUrl("BUT8"));
    httpCategoryFetch->get();
    connect(httpCategoryFetch,SIGNAL(bufferFull(const QString&,C6HttpConnection*)),this,SLOT(httpCategoryDone(const QString&,C6HttpConnection*)));
    connect(httpCategoryFetch,SIGNAL(closed()),this,SLOT(httpCategoryClosed()));
}

void C6Proto::httpCategoryDone(const QString& filename,C6HttpConnection*)
{
    QByteArray data = httpCategoryFetch->getBuffer();
    QTextStream ts(data,IO_ReadOnly );
    QString tmp;
    
    while (!ts.atEnd())
    {
        tmp = ts.readLine();
        QString indexStr = tmp.section("#",0,0);
        Category entry;
        entry.description = tmp.section("#",1);                
        QStringList subid = QStringList::split(".",indexStr);    
        
        for(int i=0; i < subid.count(); i++)
        {
            entry.subid.push_back(subid[i].toInt());         
        }       
        categoryVector.push_back(entry);    
    }
}      

void C6Proto::httpCategoryClosed()
{
    httpCategoryFetch->deleteLater();      
}      

void C6Proto::getUriFromHttp()
{
    httpUriFetch= new C6HttpConnection(getButtonUrl("BUT3"));
    httpUriFetch->get();
    connect(httpUriFetch,SIGNAL(bufferFull(const QString&,C6HttpConnection*)),this,SLOT(urlListDone(const QString&,C6HttpConnection*)));
    connect(httpUriFetch,SIGNAL(closed()),this,SLOT(httpClosed()));
}

void C6Proto::urlListDone(const QString& filename,C6HttpConnection*)
{
    QByteArray data = httpUriFetch->getBuffer();
    QTextStream ts(data,IO_ReadOnly );
    QStringList urlList;

    while (!ts.atEnd())
    {
        urlList+= ts.readLine();
    }

    for(unsigned int i=0; i < urlList.count(); i++)
    {
        if (urlList[i].contains("BUTTON_URL_111") == true)
        {
            int index =  urlList[i].find("http:");
            if (index != -1)
            {
                _nickPictureUrl = urlList[i].mid(index,urlList[i].length());
            }
        }
        else
        {
            if (urlList[i].contains("BUTTON_URL_103") == true)
            {
                int index =  urlList[i].find("http:");
                if (index != -1)
                {
                    index = urlList[i].find("http:",index+1); 
                    if (index != -1)
                    {                                  
                        _profileUrl = urlList[i].mid(index);
                    }                  
                }       
            }            
        }             
    }
}

void C6Proto::httpClosed()
{
    httpUriFetch->deleteLater();   
}

// get with BUT1, BUT2....
QString C6Proto::getButtonUrl(QString button)
{
    QString ret = QString::null;

    if (button.length() > 0)
    {
        ButtonURLType::Iterator i = _buttonURL.find(button);

        if (i != _buttonURL.end())
        {
            ret = i.data();
        }
    }
    return(ret);
}

void C6Proto::requestFileTransfer(QString const & nick,QString const &filename,int clientVersion)
{
    sendFilePath = filename;
    sendNick = nick;
    
    if (clientVersion >= OPENC6_CLIENT_TYPE)
    {
        C6MessageStyle style;
        style.setMessageType(SELF);
        style.setOperationType(REQUEST_FILE);
        sendMessage(nick,true,REQUEST_FILE_STR(filename.section('/',-1,-1)),style);
    }
    else
    {
        getIPAddress(nick);
    }
}


void C6Proto::retrieveStuffFromServer()
{
    _xcapHandler->setUserPassword(_currentLoggedNick,_currentLoggedPassword);    
    _xcapHandler->requestBuddyList();
}

void C6Proto::addBuddy(QString const &group,QString const &nick)
{
    if (_oldAccount == false)
    {         
        _xcapHandler->addBuddy(group,nick);     
    }      
}
            
void C6Proto::addBuddyToBlackList(QString const &nick)
{
    if (_oldAccount == false)
    {    
        _xcapHandler->addBuddyToBlackList(nick); 
    }      
}      

void C6Proto::addBuddyToWhiteList(QString const &nick)
{
    if (_oldAccount == false)
    {    
        _xcapHandler->addBuddyToWhiteList(nick); 
    }      
} 

void C6Proto::removeBuddy(QString const &group,QString const &nick)
{
    if (_oldAccount == false)
    {    
        _xcapHandler->removeBuddy(group,nick);     
    }      
}            
            
void C6Proto::removeBuddyFromBlackList(QString const &nick) 
{
    if (_oldAccount == false)
    {    
        _xcapHandler->removeBuddyFromBlackList(nick);     
    }      
}  

void C6Proto::removeBuddyFromWhiteList(QString const &nick) 
{
    if (_oldAccount == false)
    {    
        _xcapHandler->removeBuddyFromWhiteList(nick);     
    }      
} 

void C6Proto::addGroup(QString const &group)
{
    if (_oldAccount == false)
    {    
        _xcapHandler->addGroup(group);     
    }      
}               
            
void C6Proto::removeGroup(QString const &group)
{
    if (_oldAccount == false)
    {    
        _xcapHandler->removeGroup(group);     
    }      
}              
            
void C6Proto::renameGroup(QString const &oldGroup,QString const &newGroup)
{
    if (_oldAccount == false)
    {    
        _xcapHandler->renameGroup(oldGroup,newGroup);     
    }      
}             
            
void C6Proto::buddyListSlot(QByteArray &data)
{
    emit parseBuddyList(data);     
}
             
void C6Proto::buddyAuthSlot(QByteArray &data)
{
    emit parseBuddyAuth(data);      
}      

void C6Proto::buddyConfigSlot(QByteArray &data)
{
    emit parseBuddyConfig(data);      
}    

bool C6Proto::isOldAccount()
{
    return(_oldAccount);
}      

void C6Proto::setOldAccountMode(bool set)
{
    _oldAccount = set;      
}      

bool C6Proto::hasNAT() const
{
    return(_hasNAT);
} 

/*!
    \fn C6Proto::enterRoom(QString const& room_name)
 */
void C6Proto::enterRoom(QString const& roomName,QString const& password,QString const& oldRoom,int enterMode)
{
    int passwordLen = (password == QString::null) ? 0 : password.length();
    int oldRoomLen = (oldRoom == QString::null) ? 0 : oldRoom.length();        
    int len = 1+_currentLoggedNick.length()+1+roomName.length()+1+passwordLen+1+oldRoomLen + 4;
    
    unsigned char *savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;

    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());
    BYTE_WRITE(tocryp,roomName.length());
    STR_WRITE(tocryp,roomName.latin1(),roomName.length());
    BYTE_WRITE(tocryp,passwordLen);
    if (passwordLen > 0)
    {
        STR_WRITE(tocryp,password.latin1(),password.length());     
    }              
    BYTE_WRITE(tocryp,oldRoomLen);
    if (oldRoomLen > 0)
    {
        STR_WRITE(tocryp,roomName.latin1(),roomName.length());     
    }   

    WORD_WRITE(tocryp,((enterMode << 16) & 0xffff));
    WORD_WRITE(tocryp,(enterMode & 0xffff));    
    
    sendToSocket(CLIENT_ENTER_ROOM,savebuf,len);

    delete [] savebuf;
    emit SysLog("Request for entering in room "+roomName);
}

/*!
    \fn C6Proto::roomEntered(unsigned char *data,int packL)
 */
void C6Proto::roomEntered(unsigned char *data,int packL)
{
    const unsigned char* maxPtr =  MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;
       
    int roomNameLen;
    C6Utils::safeByteRead(data,&roomNameLen,maxPtr);    
    data++;
      
    QString roomName = QString::fromLatin1(reinterpret_cast<const char*>(data),roomNameLen);     
    data+= roomNameLen;
       
    int roomTopicLen;    
    C6Utils::safeShortRead(data,&roomTopicLen,maxPtr);    
    data+=2;
    
    QString roomTopic = QString::fromLatin1(reinterpret_cast<const char*>(data),roomTopicLen);     
    data+= roomTopicLen;   
    
    int roomAttribute;
    C6Utils::safeIntRead(data,&roomAttribute,maxPtr);
    data+=4;            
    
    int allowedUserRole;
    C6Utils::safeIntRead(data,&allowedUserRole,maxPtr);       
    data+=4;     
    
    int usersNo;
    C6Utils::safeShortRead(data,&usersNo,maxPtr);           
    data+=2;
    
    RoomUserType users;
    
    for (int i=0; i < usersNo; i++)
    {
        int userNameLen;
        C6Utils::safeByteRead(data,&userNameLen,maxPtr);    
        data++;    
        QString userName = QString::fromLatin1(reinterpret_cast<const char*>(data),userNameLen);    
        data+=userNameLen;            
        
        int userRole;
        C6Utils::safeIntRead(data,&userRole,maxPtr);       
        data+=4;     
        
        users.insert(userName,userRole);
    } 
              
    emit roomEnterInfo(roomName,roomTopic,roomAttribute,allowedUserRole,users);    
}            

/*!
    \fn C6Proto::roomError(unsigned char *data,int packL)
 */
void C6Proto::roomError(unsigned char *data,int packL)
{
    const unsigned char* maxPtr = MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;
       
    int roomNameLen;
    C6Utils::safeByteRead(data,&roomNameLen,maxPtr);    
    const QString roomName = QString::fromLatin1(reinterpret_cast<const char*>(data+1),roomNameLen);    
    data+=roomNameLen+1;   
        
    int errorCode;
    C6Utils::safeByteRead(data,&errorCode,maxPtr);    
    data++;   
    
    int errorLen;    
    C6Utils::safeShortRead(data,&errorLen,maxPtr);    
    data+=2;   
    
    QString error;
           
    if (errorLen > 0)    
    {      
        error = QString::fromLatin1(reinterpret_cast<const char*>(data),errorLen);       
    }
    
    if (errorCode != ROOMERROR_PASSWDNOK)
    {      
        emit signalError(ROOM_HASERROR,error);
    }
    else
    {
        emit askForPassword(roomName);
    }            
}

/*!
    \fn C6Proto::kickUserFromRoom(QString const &room,QString const &nick,int duration)
 */
void C6Proto::kickUserFromRoom(QString const &room,QString const &nick,int duration)
{
    QString networkIP;
    QString netmask;
    
    int len = 1+_currentLoggedNick.length()+4+4+4+1+nick.length()+   
            1+networkIP.length()+1+netmask.length()+1+room.length()+
            4;           
    
    unsigned char *savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;
    
    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());   
        
    int operationMode = ROOM_KICK | ROOM_BAN;
    WORD_WRITE(tocryp,(operationMode >> 16) & 0xffff);        
    WORD_WRITE(tocryp,(operationMode & 0xffff));
    
    int domainName = ROOM_NAME_BAN;
    WORD_WRITE(tocryp,(domainName >> 16) & 0xffff);        
    WORD_WRITE(tocryp,(domainName & 0xffff));        
    
    int clientType = 1;    
    WORD_WRITE(tocryp,(clientType>> 16) & 0xffff);        
    WORD_WRITE(tocryp,(clientType & 0xffff));   
    
    BYTE_WRITE(tocryp,nick.length());
    STR_WRITE(tocryp,nick.latin1(),nick.length());     
    
    BYTE_WRITE(tocryp,networkIP.length());
    if (networkIP.length() > 0)
    {         
        STR_WRITE(tocryp,networkIP.latin1(),networkIP.length());    
    }   
       
    BYTE_WRITE(tocryp,netmask.length());
    if (netmask.length() > 0)
    {        
        STR_WRITE(tocryp,netmask.latin1(),netmask.length());    
    }   
    
    BYTE_WRITE(tocryp,room.length());
    STR_WRITE(tocryp,room.latin1(),room.length());        
    
    WORD_WRITE(tocryp,(duration>> 16) & 0xffff);        
    WORD_WRITE(tocryp,(duration & 0xffff));   
        
    sendToSocket(CLIENT_KICK,savebuf,len);

    delete [] savebuf;
    emit SysLog("Request for kicking "+nick+ " in room "+room);   
}            

const std::vector<C6Proto::Category>& C6Proto::getRoomCategoryVector() const 
{
    return(categoryVector);
}      

C6XferProto::C6XferProto(QString const &ip,int l_port,QString const &user):
    _totalLength(0)
    ,_packetLength(0)
    ,_fragmentedPacket(false)
    ,_averageLength(0)     
    ,_chunckNumber(1)
    ,_transmitMode(false)         
{
    QString portString = QString::number(l_port);    
    OutCount = 0;
   
    _pSocket = new C6ProxySocket(0,false,true,user,user);
    static_cast<C6ProxySocket*>(_pSocket)->setDestConnection(ip,portString,C6ProxySocket::BIND);
    _pSocket->connectToHost(ip,l_port);

    connect(_pSocket,SIGNAL(proxyConnected(const QString &,int)),SLOT(proxyConnected(const QString &,int)));
    connect(_pSocket,SIGNAL(proxyError(int)),SLOT(proxyError(int)));
    connect(_pSocket,SIGNAL(error(int)),SLOT(socket_Error(int)) );
    connect(_pSocket,SIGNAL(connectionClosed()),SLOT(socket_connectionClosed()));
   
}

C6XferProto::C6XferProto(QHostAddress l_ip,int l_port,QString l_file,QString l_nick):
    _totalLength(0)
    ,_packetLength(0)
    ,_fragmentedPacket(false)           
    ,_averageLength(0) 
    ,_chunckNumber(1)     
    ,_transmitMode(true)                      
{
    OutCount = 0;
    ip = l_ip;
    port = l_port;
    file = l_file;
    nick = l_nick;

    C6Settings &settings =  C6Settings::getInstance();

    if (settings.getProxySwitch() == true)
    {
        const bool hasAccount = settings.getAuthProxySwitch();
        const bool isSocks4 = settings.getProxySocksVersion() ? false : true;
        char *pUserId = 0;
        char *pUserPsw = 0;

        if (hasAccount == true)
        {
            pUserId = const_cast<char*>(settings.getProxyUserId().latin1());
            pUserPsw = const_cast<char*>(settings.getProxyUserPsw().latin1());
        }

        _pSocket = new C6ProxySocket(this,isSocks4,hasAccount,const_cast<char*>(pUserId),const_cast<char*>(pUserPsw));

        connect(_pSocket,SIGNAL(proxyError(int)),SLOT(proxyError(int)));
        connect(_pSocket,SIGNAL(proxyConnected()),SLOT(proxyConnected()));
    }
    else
    {
        _pSocket = new QSocket();
        connect(_pSocket,SIGNAL(connected()),SLOT(socket_Connected()));
        connect(_pSocket,SIGNAL(readyRead()),SLOT(socket_ReadyRead()));
    }

    connect(_pSocket,SIGNAL(error(int)),SLOT(socket_Error(int)) );
    connect(_pSocket,SIGNAL(connectionClosed()),SLOT(socket_connectionClosed()));
}

C6XferProto::C6XferProto(int socket):
    _totalLength(0)
    ,_packetLength(0)
    ,_fragmentedPacket(false)           
    ,_averageLength(0)         
    ,_chunckNumber(1)  
    ,_transmitMode(false)                 
{
    OutCount = 1;
    _pSocket = new QSocket();
    _pSocket->setSocket(socket);
    
    connect(_pSocket,SIGNAL(readyRead()),SLOT(socket_ReadyRead()));
    connect(_pSocket,SIGNAL(error(int)),this,SLOT(socket_Error(int)));
    connect(_pSocket,SIGNAL(connectionClosed()),this,SLOT(socket_connectionClosed()));
}

C6XferProto::~C6XferProto()
{
    if (_pSocket != 0)
    {
        _pSocket->clearPendingData();
        _pSocket->close();      
        
        if (dynamic_cast<C6ProxySocket*>(_pSocket))
        {
            delete static_cast<C6ProxySocket*>(_pSocket); 
        }
        else
        {
            delete _pSocket;    
        }                                     
    }
}

void C6XferProto::wordRead(unsigned char* ptr,int *value)
{
    *value = (((int)*(ptr)) << 8) | (int)(*(ptr+1));
}


void C6XferProto::byteRead(unsigned char* ptr,unsigned char *value)
{
    *value = *ptr;
}

void C6XferProto::byteRead(unsigned char* ptr,int *value)
{
    *value = *ptr;
}


void C6XferProto::proxyError(int error)
{
    int proxyError = 0;

    switch(error)
    {
    case C6ProxySocket::METHOD_ERROR:
        proxyError = C6Proto::PROXY_METHOD_ERROR;
        break;
    case C6ProxySocket::BAD_ANSWER:
        proxyError = C6Proto::PROXY_BAD_ANSWER;
        break;
    case C6ProxySocket::BAD_AUTH:
        proxyError = C6Proto::PROXY_BAD_AUTH;
        break;
    }

    emit xferError(proxyError);
}

void C6XferProto::proxyConnected()
{
    connect(_pSocket,SIGNAL(readyRead()),SLOT(socket_ReadyRead()));
    socket_Connected();
}

void C6XferProto::proxyConnected(const QString &ip,int port)
{
    connect(_pSocket,SIGNAL(readyRead()),SLOT(socket_ReadyRead()));
    emit signalGateway(ip,port);   
}

void C6XferProto::socket_Error(int err)
{
    emit xferError(err);
}

void C6XferProto::socket_connectionClosed()
{
    emit xferClosed();
}

void C6XferProto::fire()
{
    C6Settings &settings =  C6Settings::getInstance();

    if (settings.getProxySwitch() == true)
    {
        C6ProxySocket *pProxySocket = static_cast<C6ProxySocket*>(_pSocket);
        pProxySocket->setDestConnection(ip.toString(),QString::number(port));
        QString server = settings.getProxyName();
        QString port = settings.getProxyPort();
        pProxySocket->connectToHost(server,(Q_UINT16)port.toInt());
    }
    else
    {
        _pSocket->connectToHost(ip.toString(),(Q_UINT16)port);
    }
}

void C6XferProto::socket_Connected()
{
    QString fname = file.section('/',-1,-1);
    QFile fs(file);

    int len=6+1+nick.length()+1+fname.length()+4;
    unsigned char *tocryp = new unsigned char[len];
    unsigned char *psave = tocryp;    

    WORD_WRITE(tocryp,XFER_PUSH);
    WORD_WRITE(tocryp,OutCount);
    WORD_WRITE(tocryp,len-6);
    BYTE_WRITE(tocryp,nick.length());
    STR_WRITE(tocryp,nick.latin1(),nick.length());
    BYTE_WRITE(tocryp,fname.length());
    STR_WRITE(tocryp,fname.latin1(),fname.length());
    WORD_WRITE(tocryp,(fs.size() & 0xffff0000) >> 16);
    WORD_WRITE(tocryp,fs.size() & 0x0000ffff);

    _pSocket->writeBlock((char*)psave,len);
    _pSocket->flush();

    delete [] psave;

    OutCount++;
}

void C6XferProto::socket_ReadyRead()
{
    int avail =  _pSocket->bytesAvailable();
    _totalLength+=avail;
    inComing.resize(avail);
    _pSocket->readBlock(inComing.data(),avail);
    
    unsigned char *com = reinterpret_cast<unsigned char*>(inComing.data());
    int ComServ = *com;
    
    if (ComServ == C6XferServer::XFERID && !_fragmentedPacket)
    {
        wordRead(com+4,&_packetLength);
        DataIn.resize(avail);
        memcpy(DataIn.data(),inComing.data(),avail);

        if (_totalLength-6 < _packetLength)
        {
            _fragmentedPacket = true;
            return;
        }

        Select((unsigned char*)DataIn.data(),avail,_packetLength);              // parse blocks of data
        _totalLength = 0;
    }
    else
    {
        DataIn.resize(_totalLength);
        memcpy(DataIn.data()+_totalLength-avail,inComing.data(),avail);

        if (_totalLength-6 < _packetLength)
        {         
            return;
        }         
        else
        {
            Select((unsigned char*)DataIn.data(),_totalLength,_packetLength);
            _totalLength = 0;
            _fragmentedPacket = false;
        }
    }
}

/** handle server messages */
void C6XferProto::Select(unsigned char *com,int avail,int packL)
{
    int PackL =0;
    int ComServ = *com;
    
    wordRead(com+4,&PackL);

    if (ComServ == C6XferServer::XFERID)
    {
        com++;

        switch(*com)
        {
        case C6XferServer::XFER_ACK:
            if (_transmitMode == true)
            {                
                sendNextChunk();
            }            
            break;
        case C6XferServer::XFER_STOP:
            abortXfer();
            break;
        case C6XferServer::XFER_RECEIVE:
            receivePushData(com+5);
            break;
        case C6XferServer::XFER_CHUNK_RECEIVE:
            getNextChunk(com+1);
            break;
        case C6XferServer::XFER_RECEIVE_END:
            endOfReceive();
            break;
        case C6XferServer::XFER_BAD:
            C6Utils::dumpPacket(XFER_SIG,com,PackL);
            break;
        default:
#ifdef C6DEBUG

            C6Logger::getInstance().debugPrint(XFER_SIG,"Command not recognized (%0x)\n",*com);
#endif

        }
    }
    else
    {
#ifdef C6DEBUG
        C6Logger::getInstance().debugPrint(XFER_SIG,"Invalid server ID (%02x)\n",*com);
#endif

    }

    if (avail-6 == packL)
    {      
        return;
    }      
    else
    {
        com+=(6+PackL-1);
        wordRead(com+4,&PackL);
        if (avail-packL-6 > 0)                                       // just to be sure
            Select(com,avail-packL-6,PackL);
        else
        {
#ifdef C6DEBUG
            C6Logger::getInstance().debugPrint(XFER_SIG,"Unexpected length avail-packL-6 (%d) packL (%d)\n",avail-(packL+6),PackL);
#endif

            return;
        }
    }
}

void C6XferProto::sendNextChunk()
{
    QFile fs(file);
    unsigned int pack_len = DEFAULT_FILE_TRANSFER_PACK_LEN;
    unsigned char *tocryp = new unsigned char[pack_len+2+6];
    unsigned char *psave = tocryp;

    fs.open(IO_ReadOnly);
    fs.at((_chunckNumber-1)*pack_len);

    unsigned int len = fs.readBlock((char*)(tocryp+8),pack_len);

    if (len > 0)
    {
        WORD_WRITE(tocryp,XFER_CHUNK);
        WORD_WRITE(tocryp,OutCount);
        WORD_WRITE(tocryp,len+2);
        WORD_WRITE(tocryp,len);
        _pSocket->writeBlock((char*)psave,len+2+6);

        if (fs.size())
        {
            int progress = 0;

            if (fs.size() <= _chunckNumber*pack_len)
            {
                progress = 100;
            }
            else
            {
                progress = _chunckNumber*pack_len*100/fs.size();
            }

            emit xferProgress(progress);
        }
    }
    else
    {
        WORD_WRITE(tocryp,XFER_END);
        WORD_WRITE(tocryp,OutCount);
        WORD_WRITE(tocryp,0);
        _pSocket->writeBlock((char*)psave,6);
        emit xferProgress(255);
        close();
    }

    _chunckNumber++;
    fs.close();
    _pSocket->flush();
    OutCount++;

    delete [] psave;
}


void C6XferProto::abortXfer()
{
    emit xferAborted();
}

void C6XferProto::receivePushData(unsigned char *data)
{
    int len=0;
    char buf[128];

    byteRead(data,&len);
    data++;
    memcpy(&buf,data,len);
    data+=len;
    buf[len] = 0;
    nick = QString(buf);
    byteRead(data,&len);
    data++;
    memcpy(&buf,data,len);
    data+=len;
    buf[len]=0;
    file = QString(buf);
    wordRead(data,&len);
    data+=2;
    fsize = len << 16;
    wordRead(data,&len);
    fsize |= len;

    emit signalFileSpec(file,fsize);

    sendAck();
}

/*!
    \fn C6XferProto::getNextChunk(unsigned char *data)
 */
void C6XferProto::getNextChunk(unsigned char *data)
{
    int len=0;

    QFile *fs = new QFile(C6Settings::getInstance().getFileReceivePath()+file);

    data+=4;
    wordRead(data,&len);
    data+=2;
 
    _averageLength+=len;    
    
    if (len > 0)
    {
        fs->open(IO_Append | IO_ReadWrite);
        fs->writeBlock(reinterpret_cast<char*>(data),len);
        fs->close();

        if (fsize)
        {
            emit receiveProgress((int)(_averageLength*100/fsize));
        }
    }

    delete fs;

    sendAck();
}


/*!
    \fn C6XferProto::sendAck()
 */
void C6XferProto::sendAck()
{
    unsigned char *psave = new unsigned char[6];
    unsigned char *tosend = psave;    
    WORD_WRITE(tosend,XFER_CLIENT_ACK);
    WORD_WRITE(tosend,OutCount);
    WORD_WRITE(tosend,0);
    _pSocket->writeBlock((char*)psave,6);
    _pSocket->flush();
    OutCount++;

    delete [] psave;
}


/*!
    \fn C6XferProto::endOfReceive()
 */
void C6XferProto::endOfReceive()
{
    sendEndOfTransfer();     
    emit receiveProgress(255);
}

/*!
    \fn C6XferProto::close()
 */
void C6XferProto::close()
{
   _pSocket->close();
}

/*!
    \fn C6XferProto::reset()
 */
void C6XferProto::reset()
{
    _pSocket->clearPendingData();    
    _totalLength = 0;
    _packetLength = 0;
    _fragmentedPacket = false;
    _chunckNumber = 1;
}

/*!
    \fn C6XferProto::sendEndOfTransfer()
 */
void C6XferProto::sendEndOfTransfer()
{
    unsigned char *tosend = new unsigned char[6];
    unsigned char *psave = tosend;        
    
    WORD_WRITE(tosend,XFER_STOP);
    WORD_WRITE(tosend,OutCount);
    WORD_WRITE(tosend,0);
    _pSocket->writeBlock((char*)psave,6);
    _pSocket->flush();
    OutCount++;

    delete [] psave;
}

C6XferServer::C6XferServer(int port) : QServerSocket(port,1)
{
    if (!ok())
    {
        C6Logger::getInstance().debugPrint(XFER_SIG,"Failed to bind port");      
    }
}

C6XferServer::~C6XferServer()
{}

void C6XferServer::newConnection( int socket )
{
    listenSocket = new C6XferProto(socket);
    if (listenSocket != 0)
    {          
        connect(listenSocket,SIGNAL(receiveProgress(int)),SLOT(receiveProgressSlot(int)));
        connect(listenSocket,SIGNAL(signalFileSpec(QString&, long int )),SLOT(receiveFileSpec(QString&, long int)));
        connect(listenSocket,SIGNAL(xferAborted()),SLOT(xferAborted()));
    }      
}


/*!
    \fn C6XferServer::receiveProgress(int)
 */
void C6XferServer::receiveProgressSlot(int progress)
{
    emit receiveProgress(progress);
}

/*!
    \fn C6XferServer::receiveFileSpec(QString &,long int)
 */
void C6XferServer::receiveFileSpec(QString &name,long int size)
{
    emit signalFileSpec(name,size);
}


/*!
    \fn C6XferServer::xferAborted()
 */
void C6XferServer::xferAborted()
{
    emit receiveAborted();
}

/*!
    \fn C6XferServer::stopReceive()
 */
void C6XferServer::stopReceive()
{
    if (listenSocket != 0)
    {          
        listenSocket->close();
    }      
}

/*!
    \fn C6XferServer::reset()
 */
void C6XferServer::reset()
{
    if (listenSocket != 0)
    {          
        listenSocket->reset();
    }      
}



/*!
    \fn C6Proto::processButton()
 */
void C6Proto::processButtons()
{
    // BUTTON3   
    QString tmp = getButtonUrl("BUT3");
    C6Settings::getInstance().setUrlList(tmp);
    C6Settings::getInstance().saveSettings();
    getUriFromHttp();    
    
    // BUTTON7   
    tmp = getButtonUrl("BUT7");     
    QRegExp ipNumber("\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b");
    int pos = 0;    
   
    while ((pos = ipNumber.search(tmp,pos)) >=0)
    {
        _gatewayList->append(ipNumber.cap(0));
        pos+= ipNumber.matchedLength();          
    }          
    
    // BUTTON8   
    getCategoryFromHttp();
}


/*!
    \fn C6Proto::setAuthorizationMode(QString const & mode)
 */
void C6Proto::setAuthorizationMode(QString const & mode)
{
    _configurationMode = static_cast<C6XCAPClient::CONFIG_MODE>(_xcapHandler->getConfigurationModeValue(mode));
}


/*!
    \fn C6Proto::setOfflineMessageMode(QString const & mode)
 */
void C6Proto::setOfflineMessageMode(QString const & mode)
{
    _offlineMode = static_cast<C6XCAPClient::OFFLINE_MODE>(_xcapHandler->getOfflineModeValue(mode));    
}


/*!
    \fn C6Proto::getAuthorizationMode()
 */
C6XCAPClient::CONFIG_MODE C6Proto::getConfigurationMode()
{
    return(_configurationMode);   
}



/*!
    \fn C6Proto::getOfflineMessageMode()
 */
C6XCAPClient::OFFLINE_MODE C6Proto::getOfflineMessageMode()
{
    return(_offlineMode);
}


/*!
    \fn C6Proto::sendConfigurationMode(C6XCAPClient CONFIG_MODE mode)
 */
void C6Proto::sendAndSetConfigurationMode(C6XCAPClient::CONFIG_MODE mode)
{
    _configurationMode = mode;   
    _xcapHandler->setConfiguration(mode);     
}


/*!
    \fn C6Proto::sendOfflineMessageMode(C6XCAPClient OFFLINE_MODE mode)
 */
void C6Proto::sendAndSetOfflineMessageMode(C6XCAPClient::OFFLINE_MODE mode)
{
    _offlineMode = mode; 
    _xcapHandler->setOfflineMessage(mode);      
}


/*!
    \fn C6Proto::initBuddyList()
 */
void C6Proto::initBuddyList()
{
    _xcapHandler->initBuddyList();
}


/*!
    \fn C6Proto::initAuthorization()
 */
void C6Proto::initAuthorization()
{
    _xcapHandler->initAuthorization();     
}


/*!
    \fn C6Proto::initConfiguration()
 */
void C6Proto::initConfiguration()
{
    _xcapHandler->initConfiguration(); 
}


/*!
    \fn C6Proto::setBuddyLists(ListType list,QStringList const& blacklist,QStringList const& whitelist)
 */
void C6Proto::setBuddyLists(ListType list,QStringList const& blacklist,QStringList const& whitelist)
{
    _xcapHandler->setBuddyLists(list,blacklist,whitelist,_configurationMode);    
}



/*!
    \fn C6Proto::xcapResponseOKSlot(C6XCapClient::XCAP_STATE status)
 */
void C6Proto::xcapResponseOKSlot(C6XCAPClient::XCAP_STATE status) 
{
    if (status == C6XCAPClient::XCAP_ADD_BUDDY_WHITE_LIST_STATE)
    {
        setExtendedStatus(_previousStatus,_previousOwnMessage,true);    
    }        
}
   
C6Proto::C6MessageStyle::C6MessageStyle():
_styleid(NEW_STYLE_MSG)
,_oper(ORDINARY_OP)
,_fontType(DEFAULT)
,_redComponent(0)
,_greenComponent(0)
,_blueComponent(0)
,_fontStyle(COLOR)
,_fontSize(0)
{}      
            
void C6Proto::C6MessageStyle::setMessageType(MESSAGE_TYPE type)
{
    _styleid = type;            
}                   
            
void C6Proto::C6MessageStyle::setOperationType(OPERATION_TYPE type)
{
    _oper = type;            
}  
                
C6Proto::MESSAGE_TYPE C6Proto::C6MessageStyle::getMessageType() const
{
    return _styleid;            
}                   
            
C6Proto::OPERATION_TYPE C6Proto::C6MessageStyle::getOperationType() const
{
    return _oper;            
}                   
            
void C6Proto::C6MessageStyle::setBold(bool isBold)
{
    if (isBold == true)
    { 
        _fontStyle|=BOLD;    
    }
    else
    {
        _fontStyle&=~BOLD; 
    }  
} 
                                   
bool C6Proto::C6MessageStyle::isBold() const
{
    return((_fontStyle & BOLD) == BOLD);    
}                   
            
void C6Proto::C6MessageStyle::setItalics(bool isItalic)
{
    if (isItalic == true)
    {     
        _fontStyle|=ITALICS;    
    }
    else
    {
        _fontStyle&=~ITALICS;    
    }        
}                   
            
bool C6Proto::C6MessageStyle::isItalic() const
{
    return((_fontStyle & ITALICS) == ITALICS);    
}       
            
void C6Proto::C6MessageStyle::setUnderline(bool isUnderlined)
{
    if (isUnderlined == true)
    {               
        _fontStyle|=UNDERLINE;    
    }            
    else
    {
        _fontStyle&=~UNDERLINE;                
    }    
}
                        
bool C6Proto::C6MessageStyle::isUnderline() const
{
    return((_fontStyle & UNDERLINE) == UNDERLINE);    
}     
            
int C6Proto::C6MessageStyle::getFontStyle() const
{
    return _fontStyle;            
}                   
            
void C6Proto::C6MessageStyle::setRGB(int r,int g,int b)
{
    _redComponent = r;
    _greenComponent = g;
    _blueComponent = b;            
}                   
                
void C6Proto::C6MessageStyle::getRGB(int &r,int &g,int &b)
{
    r = _redComponent;
    g = _greenComponent;
    b = _blueComponent;                            
}                   
            
void C6Proto::C6MessageStyle::setFontTypeNo(int fontType)
{
    _fontType = fontType;            
}        
                       
void C6Proto::C6MessageStyle::setFontStyle(int style)
{
    _fontStyle = style;    
}                   
            
int C6Proto::C6MessageStyle::getFontTypeNo() const
{
    return _fontType;
}                   
            
void C6Proto::C6MessageStyle::setFontSizePt(int fontSize)
{
    _fontSize = fontSize;            
}            
            
int C6Proto::C6MessageStyle::getFontSizePt() const
{
    return _fontSize;
}          

C6Proto::RoomAttribute::RoomAttribute():
        _isPublic(true),
        _isSystem(false),
        _isTemporary(true),      
        _isPasswordProtected(false)            
{
}      

int C6Proto::RoomAttribute::pack()
{
    int attribute = 0;
    
    attribute |= (_isPublic == true) ? 1 : 0;
    attribute |= (_isSystem == true) ? 2 : 0;    
    attribute |= (_isTemporary == true) ? 4 : 0;    
    attribute |= (_isPasswordProtected == true) ? 128 : 0;     
    return attribute;   
}
      
void C6Proto::RoomAttribute::unpack(int attribute)
{
    _isPublic = (attribute & 1);
    _isSystem = (attribute & 2);
    _isTemporary = (attribute & 4);        
    _isPasswordProtected = (attribute & 128);
}     
               
void C6Proto::RoomAttribute::setPublic(bool set)
{
    _isPublic = set;   
}

void C6Proto::RoomAttribute::setSystem(bool set)
{
    _isSystem = set;   
} 

void C6Proto::RoomAttribute::setTemporary(bool set)
{
    _isTemporary = set;   
} 

void C6Proto::RoomAttribute::setProfileLess(bool set)
{}       

void C6Proto::RoomAttribute::setReadOnly(bool set)
{}  

void C6Proto::RoomAttribute::setTOP(bool set)
{}    
       
void C6Proto::RoomAttribute::setModerated(bool set)
{}
 
void C6Proto::RoomAttribute::setPasswordProtected(bool set)
{
    _isPasswordProtected = set;   
} 
void C6Proto::RoomAttribute::setClonable(bool set)
{} 

void C6Proto::RoomAttribute::setGuest(bool set)
{}       

void C6Proto::RoomAttribute::setGuestCanWrite(bool set)
{}     

void C6Proto::RoomAttribute::setNickRestriction(bool set)
{} 

void C6Proto::RoomAttribute::setIPRestriction(bool set)
{}      

void C6Proto::RoomAttribute::setLog(bool set)
{}    

void C6Proto::RoomAttribute::setExternalChat(bool set)
{}  

bool C6Proto::RoomAttribute::isPublic() const
{
    return(_isPublic);   
}

bool C6Proto::RoomAttribute::isSystem() const
{
    return(_isSystem);   
}     

bool C6Proto::RoomAttribute::isTemporary() const
{
    return(_isTemporary);   
}    

bool C6Proto::RoomAttribute::isProfileLess() const
{}
    
bool C6Proto::RoomAttribute::isReadOnly() const
{}  

bool C6Proto::RoomAttribute::isTOP() const
{}        

bool C6Proto::RoomAttribute::isModerated() const
{}  

bool C6Proto::RoomAttribute::isPasswordProtected() const
{
    return(_isPasswordProtected);   
}
  
bool C6Proto::RoomAttribute::isClonable() const
{}  

bool C6Proto::RoomAttribute::hasGuest() const
{}  

bool C6Proto::RoomAttribute::guestCanWrite() const
{}

bool C6Proto::RoomAttribute::hasNickRestriction() const
{} 

bool C6Proto::RoomAttribute::hasIPRestriction() const
{} 

bool C6Proto::RoomAttribute::hasLog() const
{}       

bool C6Proto::RoomAttribute::hasExternalChat() const
{}  

/*!
    \fn C6Proto::getProfileUrl() const
 */
const QString& C6Proto::getProfileUrl() const
{
    return(_profileUrl);
}



/*!
    \fn C6Proto::getOfflineMessage()
 */
void C6Proto::getOfflineMessage()
{
    int len = 1+_currentLoggedNick.length();
    
    unsigned char *savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;

    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());
    sendToSocket(GET_OF_MESSAGE,savebuf,len);

    delete [] savebuf;
    emit SysLog("Request for offline message");
}


/*!
    \fn C6Proto::removeOfflineMessage(int id)
 */
void C6Proto::removeOfflineMessage(int id)
{
    int len = 1+_currentLoggedNick.length()+2+4;
    
    unsigned char *savebuf = new unsigned char[len+PACKET_HEADER_LEN*2];
    unsigned char *tocryp = savebuf + PACKET_HEADER_LEN*2;

    BYTE_WRITE(tocryp,_currentLoggedNick.length());
    STR_WRITE(tocryp,_currentLoggedNick.latin1(),_currentLoggedNick.length());
    
    WORD_WRITE(tocryp,0x0001);
    WORD_WRITE(tocryp,((id & 0xffff0000) >> 16));        
    WORD_WRITE(tocryp,id & 0x0000ffff);         
    
    sendToSocket(DEL_OF_MESSAGE,savebuf,len);

    delete [] savebuf;
    emit SysLog("Request for offline message");
}


/*!
    \fn C6Proto::receiveOfflineMessage(unsigned char *data,int packL)
 */
void C6Proto::receiveOfflineMessage(unsigned char *data,int packL)
{
    const unsigned char* maxPtr = MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;
        
    int messageId;
    C6Utils::safeIntRead(data,&messageId,maxPtr);
    data+=4;    
    
    if (messageId != 0)
    {
        int nickLen;
        C6Utils::safeByteRead(data,&nickLen,maxPtr);           
        data++;    
        unsigned char* pNick = new unsigned char[nickLen];
        C6Utils::safeStringCopy(pNick,data,nickLen,maxPtr); 
        QString fromNick = QString::fromLatin1((const char*)pNick,nickLen);       
        delete [] pNick;    
        
        data+=nickLen;
        
        int myNickLen;
        C6Utils::safeByteRead(data,&myNickLen,maxPtr);           
        data+=myNickLen+1;            
        
        int timeLen;    
        C6Utils::safeByteRead(data,&timeLen,maxPtr);     
        data++;    
        unsigned char* pTime = new unsigned char[timeLen];    
        C6Utils::safeStringCopy(pTime,data,timeLen,maxPtr); 
        QString time = QString::fromLatin1((const char*)pTime,timeLen);       
        data+=timeLen;    
        delete [] pTime;    
        
        data++;    // carrier
        int messageLen;
        C6Utils::safeShortRead(data,&messageLen,maxPtr);      
        data+=4;    
        int textLen = messageLen - 2;    
        unsigned char* pText = new unsigned char[textLen];        
        C6Utils::safeStringCopy(pText,data,textLen,maxPtr); 
        QString text = QString::fromLatin1((const char*)pText,textLen);       
        delete [] pText;    
        
        removeOfflineMessage(messageId);
              
        emit notifyReportMessage(fromNick,text,time);    
        emit SysLog("Receiving offline message id "+QString::number(messageId)+" from "+fromNick);
    }          
}

bool C6Proto::isConnected() const
{
    return(_pSocket->state() == QSocket::Connected);
}      

void C6Proto::receiveKickBanError(unsigned char *data,int packL)
{
    const unsigned char* maxPtr = MAX_PTR(packL);
    data+=SKIP_PACKET_HEADER;
       
    int messageType;
    C6Utils::safeIntRead(data,&messageType,maxPtr);
    data+=4;    
    
    int messageLen;
    C6Utils::safeShortRead(data,&messageLen,maxPtr);      
    data+=2;        
    
    unsigned char* pText = new unsigned char[messageLen];        
    C6Utils::safeStringCopy(pText,data,messageLen,maxPtr); 
    QString text = QString::fromLatin1((const char*)pText,messageLen);       
    delete [] pText;
    
    emit signalError(KICK_BAN_ERROR,text);    
}      


