/***************************************************************************
 *   Copyright (C) 2004 by yunfan                                          *
 *   yunfan_zg@163.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.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "evalogin.h"
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include "qq_crypt.h"
#include "evautil.h"
 
LoginPacket::LoginPacket(unsigned char loginMode)
	: OutPacket(QQ_CMD_LOGIN, true),
	mLoginMode(loginMode)
{
}

LoginPacket::LoginPacket(const LoginPacket &rhs)
	:OutPacket(rhs)
{
	mLoginMode = rhs.getLoginMode();
}

LoginPacket::~LoginPacket()
{
}

LoginPacket &LoginPacket::operator=(const LoginPacket &rhs)
{
	*((OutPacket *)this) = (OutPacket)rhs;
	mLoginMode = rhs.getLoginMode();
        return *this;
}

int LoginPacket::putBody(unsigned char *buf) 
{
	memcpy(buf, iniKey, QQ_KEY_LENGTH);
	
	unsigned char *login = 
			(unsigned char*)malloc(QQ_LOGIN_DATA_LENGTH * 
						sizeof(unsigned char));	
	int loginLen=50;
	unsigned char *passwordKey = getPasswordKey();
	if(passwordKey==NULL){
		fprintf(stderr, "LoginPacket->putBody: no password key avalible\n");
		return 0;
	}
	qq_crypt(ENCRYPT,NULL, 0, passwordKey, login, &loginLen);
		
	memset(login+16, 0, 7);
	memcpy(login+23, login_23_51, 29);
	login[52] = mLoginMode;
	memcpy(login+53, login_53_68, 16);
	
	unsigned char *encrypted = 
			(unsigned char*)malloc(200 * sizeof(unsigned char));
	int enLen=200;
	qq_crypt(ENCRYPT, login, QQ_LOGIN_DATA_LENGTH, iniKey, encrypted, &enLen);
	
	memcpy(buf+QQ_KEY_LENGTH, encrypted, enLen);	
	free(login);
	free(encrypted);
	return QQ_KEY_LENGTH + enLen;
}

/* =========================================================== */

LoginReplyPacket::LoginReplyPacket(unsigned char *buf, int len)
	: InPacket(buf, len)
{ 
}   

LoginReplyPacket::LoginReplyPacket(const LoginReplyPacket &rhs)
	: InPacket(rhs)
{ 	
	replyCode = rhs.getReplyCode();
	redirectedIP = rhs.getRedirectedIP();
	redirectedPort = rhs.getRedirectedPort();
	
	qqNum = rhs.getQQ();
	IP = rhs.getMyIP();
	port = rhs.getMyPort();
	loginTime = rhs.getLoginTime();
	serverIP = rhs.getServerIP();
	serverPort = rhs.getServerPort();
	lastLoginIP = rhs.getLastLoginIP();
	lastLoginTime = rhs.getLastLoginTime();
	replyMessage = rhs.getReplyMessage();
} 

LoginReplyPacket &LoginReplyPacket::operator=(const LoginReplyPacket &rhs)
{
	*((InPacket *)this) = (InPacket)rhs;
	replyCode = rhs.getReplyCode();
	redirectedIP = rhs.getRedirectedIP();
	redirectedPort = rhs.getRedirectedPort();
	
	qqNum = rhs.getQQ();
	IP = rhs.getMyIP();
	port = rhs.getMyPort();
	loginTime = rhs.getLoginTime();
	serverIP = rhs.getServerIP();
	serverPort = rhs.getServerPort();
	lastLoginIP = rhs.getLastLoginIP();
	lastLoginTime = rhs.getLastLoginTime();
	replyMessage = rhs.getReplyMessage();
        return *this;
}

void LoginReplyPacket::parseBody() 
{
	replyCode = decryptedBuf[0];
	switch(replyCode) {     
	case QQ_LOGIN_REPLY_OK:
		{
			short tmp2;
			int tmp4;
			setSessionKey(decryptedBuf+1);
			
			// now we can set the file session key			
			char *fsbuf = (char *)malloc((4+ QQ_KEY_LENGTH) * sizeof(char));
			int qqid = htonl(getQQ());
			memcpy(fsbuf, &qqid, 4);
			memcpy(fsbuf+4, getSessionKey(), QQ_KEY_LENGTH);
			setFileSessionKey((unsigned char *)EvaUtil::doMd5(fsbuf, 4 + QQ_KEY_LENGTH));
			
			memcpy(&tmp4, decryptedBuf + QQ_KEY_LENGTH + 1, 4);
			qqNum = ntohl(tmp4);
			// 021-024  user IP
			memcpy(&tmp4, decryptedBuf + 21, 4); 
			IP = ntohl(tmp4);
			// 025-026 user port
			memcpy(&tmp2, decryptedBuf+25, 2);
			port = ntohs(tmp2);
			// 027-030 server IP
			memcpy(&tmp4, decryptedBuf + 27, 4);
			serverIP = ntohl(tmp4);
			// 031-032 server port
			memcpy(&tmp2, decryptedBuf+31, 2);
			serverPort = ntohs(tmp2);
			// 033-036  login time    
			memcpy(&tmp4, decryptedBuf+33, 4);
			loginTime = ntohl(tmp4);
			
			// 123-126  user IP when last login
			memcpy(&tmp4, decryptedBuf+123, 4);
			lastLoginIP = ntohl(lastLoginIP);
			// 127-130  last login time             
			memcpy(&tmp4, decryptedBuf+127, 4);
			lastLoginTime = ntohl(tmp4);
			// 131-138 unknow bytes
			break;
		}
	case QQ_LOGIN_REPLY_PWD_ERROR:
		// message from server when password is wrong. the messege is encoded by "GBK"
		{
			char *tmpMsg = (char*)malloc( bodyLength * sizeof(char));
			memcpy(tmpMsg, decryptedBuf+1, bodyLength-1);
			tmpMsg[bodyLength-1]=0; 
			replyMessage.assign(tmpMsg);
			free(tmpMsg);
			break;
		}
	case QQ_LOGIN_REPLY_REDIRECT:
		// redirect user to another server for balance reason
		{
			short tmp2;
			int tmp4;
			// 001-004 user qq number
			memcpy(&tmp4, decryptedBuf + QQ_KEY_LENGTH + 1, 4);
			qqNum = ntohl(tmp4);
			// 005-008  the new server IP address
			memcpy(&tmp4, decryptedBuf+5, 4);
			redirectedIP = ntohl(tmp4);
			// 009-010  the new server's Port number              
			memcpy(&tmp2, decryptedBuf+9, 2);
			redirectedPort = ntohs(tmp2);
			break;
		}
	default:
		replyCode = QQ_LOGIN_REPLY_MISC_ERROR;
		break;
	}
}

/* =========================================================== */

LogoutPacket::LogoutPacket()
	: OutPacket(QQ_CMD_LOGOUT, false)
{
 	sequence = 0xFFFF;
}

LogoutPacket::LogoutPacket(const LogoutPacket &rhs)
	: OutPacket(rhs)
{
}

LogoutPacket &LogoutPacket::operator=(const LogoutPacket &rhs)
{
	*((OutPacket *)this) = (OutPacket)rhs;
        return *this;
}

int LogoutPacket::putBody(unsigned char *buf) 
{    
	unsigned char *pwKey = Packet::getPasswordKey();
	if(pwKey==NULL){
		fprintf(stderr, "LogoutPacket->putBody: no password key avalible\n");
		return 0;
	}
	memcpy(buf, pwKey, QQ_KEY_LENGTH);
	return QQ_KEY_LENGTH;
}

/* =========================================================== */

KeepAlivePacket::KeepAlivePacket()
	: OutPacket(QQ_CMD_KEEP_ALIVE, true) 
{
}

KeepAlivePacket::KeepAlivePacket(const KeepAlivePacket &rhs)
	: OutPacket(rhs) 
{
}

KeepAlivePacket &KeepAlivePacket::operator=(const KeepAlivePacket &rhs )
{
	*((OutPacket *)this) = (OutPacket)rhs;
        return *this;
}

int KeepAlivePacket::putBody(unsigned char *buf) 
{
        int qq = htonl(getQQ());
	memcpy(buf, &qq, 4); 
        //buf[0] = (Q_UINT8)(qq>>24);
        //buf[1] = (Q_UINT8)((qq&0x00ff0000)>>16);
        //buf[2] = (Q_UINT8)((qq&0x0000ff00)>>8);
        //buf[3] = (Q_UINT8)(qq&0x000000ff);
        return 4; 
}

/* =========================================================== */

int KeepAliveReplyPacket::onlineUsers=0;

KeepAliveReplyPacket::KeepAliveReplyPacket(unsigned char *buf, int len) 
	: InPacket(buf, len) 
{
}   

KeepAliveReplyPacket::KeepAliveReplyPacket(const KeepAliveReplyPacket &rhs)
	: InPacket(rhs) 
{
	onlineUsers = rhs.numOnlineUsers();
	myIP = rhs.getMyIP();
	myPort = rhs.getMyPort();
}

KeepAliveReplyPacket &KeepAliveReplyPacket::operator=(const KeepAliveReplyPacket &rhs)
{
	*((InPacket *)this) = (InPacket)rhs;
	onlineUsers = rhs.numOnlineUsers();
	myIP = rhs.getMyIP();
	myPort = rhs.getMyPort();
        return *this;	
}
 
void KeepAliveReplyPacket::parseBody()
{
	int sec = 0, offset = 0;
	char section[10][256];
	for(int i=0; i<bodyLength; i++){
		if(sec>5) printf("Keep Alive -- number of fields greater than 5\n");
		if(decryptedBuf[i]==KA_DIVIDER){
			section[sec][offset] = 0;
			sec++;
			offset=0;
			continue;
		}
		section[sec][offset++]=decryptedBuf[i]; 
	}
	section[sec][offset]=0;
	
	if(sec != 4){
		printf("Keep Alive -- number of fields wrong!\n");
		return;
	}

	onlineUsers = atoi(section[2]);
	if(onlineUsers == 0 ){
		printf("KeepAliveReplyPacket -- parse online users error!\n");
		return;
	}
       
	myIP.assign( section[3]);
	myPort = atoi(section[4]);
}


