/***************************************************************************
 *   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 "evapacketmanager.h"
#include "evausersetting.h"
#include "evaconnecter.h"
#include <qdatetime.h>
#include <qtimer.h>
#include <qtextcodec.h>
#include <stdlib.h>
#include <map>

EvaPacketManager::EvaPacketManager(EvaUser *user, EvaConnecter *connecter)
{
	codec = QTextCodec::codecForName("GB18030");
	this->user = user;
	addingBuddyQQ = 0;
	deletingBuddyQQ = 0;
	processQunID = 0;
	qunMemberInfoFinished = false;
	OutPacket::setQQ(user->getQQ());
	Packet::setPasswordKey((unsigned char *)(user->getMd5Password()));
	this->connecter = connecter;
	Packet::setUDP(connecter->getConnectionType() == EvaNetwork::UDP);
	QObject::connect(connecter, SIGNAL(newPacket()), this, SLOT(newPacketSlot()));
	QObject::connect(connecter, SIGNAL(networkException(int)), this, SLOT(networkExceptionSlot(int)));
	QObject::connect(connecter, SIGNAL(packetException(int)), this, SLOT(packetExceptionSlot(int)));
	
	timer = new QTimer(this);
	QObject::connect(timer, SIGNAL(timeout()), SLOT(timerSlot()) );
}

EvaPacketManager::~EvaPacketManager()
{
	if(timer->isActive()){
		timer->stop();
	}
	delete timer;
	if(user) delete user;
	if(connecter) delete connecter;
}

void EvaPacketManager::newPacketSlot()
{
	InPacket *packet = connecter->getInPacket();
	if(packet==NULL){
		fprintf(stderr, "grab packet error: NULL pointer!\n");
		return;
	}
	parsePacket(packet);
}

void EvaPacketManager::networkExceptionSlot(int exp)
{
	printf("network exception: %d\n", exp);
	emit networkException(exp);
}

void EvaPacketManager::packetExceptionSlot(int cmd)
{
	printf("packet exception: (cmd)0x%4x\n",cmd);
	emit packetException(cmd);
}

void EvaPacketManager::timerSlot()
{
	connecter->append(new KeepAlivePacket());
	receivedPacketList.clear();
	receivedCacheList.clear();
}

void EvaPacketManager::redirectTo(const int ip, const short port)
{
	connecter->redirectTo(ip, port);
}

void EvaPacketManager::saveBuddyQQ(const int id, const short seq)
{
	std::map<short, int>::iterator iter = sendRemoveCacheList.find(seq);
	if( iter != sendRemoveCacheList.end()) return ;
	
	sendRemoveCacheList[seq] = id;
}

void EvaPacketManager::removeSequence(const short seq)
{
	std::map<short, int>::iterator iter = sendRemoveCacheList.find(seq);
	if( iter == sendRemoveCacheList.end()) return;
	sendRemoveCacheList.erase(iter);
}

const int EvaPacketManager::getSavedBuddyQQ(const short seq)
{
	std::map<short, int>::iterator iter = sendRemoveCacheList.find(seq);
	if(iter == sendRemoveCacheList.end()) return -1;
	
	return sendRemoveCacheList[seq];
}

void EvaPacketManager::parsePacket(InPacket *packet)
{
	int index = receivedPacketList.findIndex(packet->hashCode());
	if(index != -1 && packet->getCommand() != QQ_CMD_RECV_IM) {
		delete packet;
		return;
	}
	receivedPacketList.append(packet->hashCode());
	
	switch(packet->getCommand()){
	case QQ_CMD_LOGIN:
		processLoginReply(packet);
		break;
	case QQ_CMD_KEEP_ALIVE:
		processKeepAliveReply(packet);
		break;
	case QQ_CMD_GET_USER_INFO:
		printf("user info\n"); 
		processGetUserInfoReply(packet);
		break;
	case QQ_CMD_CHANGE_STATUS:
		printf("change status reply\n");
		processChangeStatusReply(packet);
		break;
	case QQ_CMD_GET_FRIEND_LIST:
		printf("friend list\n");
		processGetFriendListReply(packet);
		break;
	case QQ_CMD_GET_FRIEND_ONLINE:
		//printf("online-friend list\n");
		processGetOnlineFriendReply(packet);
		break;
	case QQ_CMD_SEND_IM:
		printf("send im reply\n");
		processSendIMReply(packet);
		break;
	case QQ_CMD_RECV_IM:
		printf("received new message\n");
		processReceiveIM(packet);
		break;
	case QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS:
		printf("friend change status\n");
		processFriendChangeStatus(packet);
		break;
	case QQ_CMD_GROUP_NAME_OP:
		printf("upload/download group names reply\n");
		processGroupNameOp(packet);
		break;
	case QQ_CMD_DOWNLOAD_GROUP_FRIEND:
		printf("grouped friends reply\n");
		processDownloadGroupFriendReply(packet);
		break;	
	case QQ_CMD_UPLOAD_GROUP_FRIEND:
		printf("upload grouped friend reply\n");
		processUploadGroupFriendReply(packet);
		break;
	case QQ_CMD_DELETE_FRIEND:
		printf("delete friend reply\n");
		processDeleteFriendReply(packet);
		break;
	case QQ_CMD_ADD_FRIEND:
		printf("add friend reply\n");
		processAddFriendReply(packet);
		break;
	case QQ_CMD_ADD_FRIEND_AUTH:
		printf("add friend auth reply\n");
		processAddFriendAuthReply(packet);
		break;				
	case QQ_CMD_RECV_MSG_SYS:
		printf("system message\n");
		processSystemNotification(packet);
		break;
	case QQ_CMD_MODIFY_INFO:
		printf("received modify info\n");
		processModifyInfoReply(packet);
		break;
	case QQ_CMD_SEARCH_USER:
		printf("search reply\n");
		processSearchUserReply(packet);
		break;
	case QQ_CMD_DELETE_ME:
		printf("delete me reply\n");
		processDeleteMeReply(packet);
		break;
	case QQ_CMD_REQUEST_LOGIN_TOKEN:
		printf("got login token\n");
		processRequestLoginTokenReply(packet);
		break;
	case QQ_CMD_QUN_CMD:
		printf("got Qun operation reply\n");
		processQunReply(packet);
		break;
	case QQ_CMD_GET_LEVEL:
		printf("got level reply\n");
		processGetLevelReply(packet);
		break;
	case QQ_CMD_REQUEST_KEY:
		printf("got keys reply\n");
		processRequestKeyReply(packet);
		break;
	case QQ_CMD_REQUEST_EXTRA_INFORMATION:
		printf("got extra info reply\n");
		processRequestExtraInfoReply(packet);
		break;
	case QQ_CMD_SIGNATURE_OP:
		printf("got signature op reply\n");
		processSignatureReply(packet);
		break;
	}
        delete packet;
}

void EvaPacketManager::doRequestLoginToken()
{
	connecter->append(new RequestLoginTokenPacket());
}

void EvaPacketManager::doLogin()
{
	if(! Packet::isLoginTokenSet()){
		doRequestLoginToken();
		return;
	}
	unsigned char mode = QQ_LOGIN_MODE_INVISIBLE;
	if(user->getStatus() == EvaUser::Eva_Online)
		mode = QQ_LOGIN_MODE_NORMAL;
	Packet::setPasswordKey((unsigned char *)(user->getMd5Password()));
	connecter->append(new LoginPacket(mode));
}

void EvaPacketManager::processRequestLoginTokenReply(const InPacket *in)
{
	if(Packet::isLoginTokenSet()) return;
	RequestLoginTokenReplyPacket *packet = new RequestLoginTokenReplyPacket();
	packet->setInPacket(in);
	bool isWrong = packet->parse();
	delete packet;
	if(!isWrong){
		emit serverBusy();
		return;
	}
	user->loginManager()->finishedCommand(QQ_CMD_REQUEST_LOGIN_TOKEN);
	// here, we've got login token, therefore, try to log in
	doLogin();
}

void EvaPacketManager::processLoginReply(const InPacket *in)
{
	// if client key is set, the user has logged in.
	if(Packet::isClientKeySet()) 
		return;
	if(user->loginManager()->isCommandFinished(QQ_CMD_LOGIN))
		return;
        LoginReplyPacket *packet = new LoginReplyPacket();
        packet->setInPacket(in);
	if(!packet->parse()) { 
		printf("parse error\n"); 
		delete packet;
		emit serverBusy(); // if parse error, we just emit a serverBusy signal so that we can have another try
		return;
	}
	switch(packet->getReplyCode())
	{
	case QQ_LOGIN_REPLY_OK:
		{
		printf("user \"%d\" logged in!\n", user->getQQ());
		user->loginManager()->finishedCommand(QQ_CMD_LOGIN);
		connecter->append(new ChangeStatusPacket(EvaUser::getStatusCode(user->getStatus())));
		connecter->append(new EvaRequestKeyPacket(QQ_REQUEST_FILE_AGENT_KEY));
		//connecter->append(new EvaRequestKeyPacket(QQ_REQUEST_UNKNOWN_KEY));
		if(user->isBuddiesLoaded())
			connecter->append(new GetOnlineFriendsPacket());
		if(!timer->isActive()){
			timer->start(60000, false);
		}else
			printf("impossible! \n");
		emit loginOK();
		}
		break;
	case QQ_LOGIN_REPLY_REDIRECT:
		printf("EVA redirect to: %8x, %d\n", packet->getRedirectedIP(), packet->getRedirectedPort());
		if(packet->getRedirectedIP() == 0) {
			emit serverBusy();
		}else
			redirectTo(packet->getRedirectedIP(),packet->getRedirectedPort());
		break;
	case QQ_LOGIN_REPLY_PWD_ERROR:
		printf("something error:%s\n",packet->getReplyMessage().c_str());
		emit wrongPassword(codec->toUnicode(packet->getReplyMessage().c_str()));
		break;
	case QQ_LOGIN_REPLY_MISC_ERROR:
		printf("some unknown error:%s\nhaving another try ...\n",packet->getReplyMessage().c_str());
		emit serverBusy();
		break;
        default:
                printf("unknown reply code\n");
	}
	delete packet;
}

void EvaPacketManager::doLogout( )
{
	if(timer->isActive())
		timer->stop();
	connecter->stop();
	if(user->getStatus() != EvaUser::Eva_Offline){
		for(int i=0; i<4; i++)
			connecter->append(new LogoutPacket());
		user->setStatus(EvaUser::Eva_Offline);
	}
	Packet::clearAllKeys();
	emit logoutOK();
}

void EvaPacketManager::doGetUserInfo( const int id )
{
	connecter->append(new GetUserInfoPacket(id));
}

void EvaPacketManager::processGetUserInfoReply( const InPacket * in )
{
	GetUserInfoReplyPacket *packet = new GetUserInfoReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	ContactInfo info = packet->contactInfo();
	std::string strID = info.at(ContactInfo::Info_qqID);
	int id = atoi(strID.c_str());
	if( id == user->getQQ()){
		user->setDetails(info);
		user->loginManager()->finishedCommand(QQ_CMD_GET_USER_INFO);
		emit myInfoReady();
	}else{
		user->getFriendList().addContactInfoTo(id, info);
	}
	delete packet;
	user->saveGroupedBuddyList();
	emit userInfoReady(convertDetails(info));
}

void EvaPacketManager::doChangeStatus( EvaUser::UserStatus newStatus )
{
	user->setStatus( newStatus );
	connecter->append(new ChangeStatusPacket(EvaUser::getStatusCode(newStatus)));
}

void EvaPacketManager::processChangeStatusReply( const InPacket * in )
{
	ChangeStatusReplyPacket *packet = new ChangeStatusReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	if(packet->isAccepted()){  // if change status failed,  in most cases it's because of connection problem, 
		user->loginManager()->finishedCommand(QQ_CMD_CHANGE_STATUS);    // so we simply emit a offline signal
		switch(user->getStatus()){
		case EvaUser::Eva_Online:
			emit onlineReady();
			break;
		case EvaUser::Eva_Offline:
			if(timer->isActive())
				timer->stop();
			connecter->stop();
			Packet::clearAllKeys();
			emit offlineReady();
			break;	
		case EvaUser::Eva_Invisible:
			emit invisibleReady();
			break;
		case EvaUser::Eva_Leave:
			emit leaveReady();
			break; 
		}
	}else{
		if(timer->isActive())
			timer->stop();
		connecter->stop();
		emit offlineReady();    // if we meet any problem, just emit offline signal
	}
	delete packet;
}

void EvaPacketManager::doGetAllFriends( )
{
	user->getFriendList().clearFriendList();
	connecter->append(new GetFriendListPacket());
}

void EvaPacketManager::processGetFriendListReply( const InPacket * in )
{
	GetFriendListReplyPacket *packet = new GetFriendListReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	friendItemList gotList = packet->getFriendList();
	friendItemList::iterator iter;
	for(iter = gotList.begin(); iter!= gotList.end(); ++iter){
		QQFriend frd;
		frd.setFriendItem(*iter);
		user->getFriendList().addFriend(frd);
	}
	if(packet->getPosition()!=QQ_FRIEND_LIST_POSITION_END){
		connecter->append(new GetFriendListPacket(packet->getPosition()));
	}else{
		emit friendListReady(); // EvaMain class will set the loginManager
	}
	delete packet;
}

void EvaPacketManager::doSendMessage( const int receiver, const bool isNormal, QString & message, const char fontSize, 
					const bool u, const bool i, const bool b, 
					const char blue, const char green, const char red )
{	
	if(!user->loginManager()->isReady()) {
		printf("Client Not ready, ignore sending request!\n");
		return;
	}
	QString rNick = codec->toUnicode( user->getFriendList().getFriend(receiver)->getNick().c_str());
	QString sNick = codec->toUnicode(user->getDetails().at(ContactInfo::Info_nick).c_str());
	QDateTime time = QDateTime::currentDateTime(Qt::LocalTime);	
	user->getSetting()->saveMessage(receiver,  user->getQQ(), sNick, receiver, rNick,
				isNormal, message, time, fontSize, u, i, b, blue, green, red);
	SendTextIMPacket *packet = new SendTextIMPacket();
	packet->setReceiver(receiver);
	packet->setFontSize(fontSize);
	packet->setUnderline(u);
	packet->setItalic(i);
	packet->setBold(b);
	packet->setBlue(blue);
	packet->setGreen(green);
	packet->setRed(red);
	packet->setAutoReply(isNormal);
	QCString str = codec->fromUnicode(message);
	packet->setMessage(str.data());
	saveBuddyQQ(receiver, packet->getSequence());
	connecter->append(packet);
}

void EvaPacketManager::processSendIMReply( const InPacket * in )
{
	SendIMReplyPacket *packet = new SendIMReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	int id = getSavedBuddyQQ(packet->getSequence());
	if(id==-1) return;
	removeSequence(packet->getSequence());
	emit sentMessageResult(id, packet->isSentOK());	
	delete packet;
}

void EvaPacketManager::processKeepAliveReply( const InPacket * in )
{
	KeepAliveReplyPacket *packet = new KeepAliveReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	numOnlineUsers = packet->numOnlineUsers();
	delete packet;
	connecter->append(new GetOnlineFriendsPacket());
}

void EvaPacketManager::processGetOnlineFriendReply( const InPacket * in )
{
	GetOnlineFriendReplyPacket *packet = new GetOnlineFriendReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	onlineList list = packet->getOnlineFriendList();
	onlineList::iterator iter;
	for(iter = list.begin(); iter!=list.end(); ++iter){
		user->getFriendList().addOnlineFriendEntryTo(iter->getQQ(), *iter);
	}
	if(packet->getPosition() != QQ_FRIEND_ONLINE_LIST_POSITION_END){
		connecter->append(new GetOnlineFriendsPacket(packet->getPosition()));
	}
	delete packet;
}

void EvaPacketManager::processFriendChangeStatus( const InPacket * in )
{
	FriendChangeStatusPacket *packet = new FriendChangeStatusPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	
	user->getFriendList().updateFriendIP(packet->getQQ(), packet->getIP());
	user->getFriendList().updateFriendPort(packet->getQQ(), packet->getPort());
	
	const QQFriend *frd = (user->getFriendList()).getFriend(packet->getQQ());
	
	if( frd && (frd->getStatus() != packet->getStatus()) ){
		user->getFriendList().updateFriendStatus(packet->getQQ(), packet->getStatus());
		emit friendStatusChanged(packet->getQQ());
	}
	delete packet;
}

void EvaPacketManager::processReceiveIM( const InPacket * in )
{
	ReceiveIMPacket *packet = new ReceiveIMPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	
	ReceiveIMReplyPacket *packetReply = new ReceiveIMReplyPacket(packet->getReplyKey());
	packetReply->setSequence(packet->getSequence());
	connecter->append(packetReply);
	
	int index = receivedCacheList.findIndex(packet->hashCode());
	if(index != -1 ){
		delete packet;
		return;
	}
	
	receivedCacheList.append(packet->hashCode());

	switch(packet->getIMType()){
	case 0x0010:{
		int len = packet->getBodyLength();
		const unsigned char *buf = packet->getBodyData();
		printf("COMMAND: 0X0010s\n");
		for(int i=0; i<len; i++){
			if(!(i%8)) printf("\n");
			char t = buf[i];
			printf("%2x ", (uint8_t)t);
		}
		printf("\n");
		}
		break;
	case QQ_RECV_IM_TO_BUDDY:
	case QQ_RECV_IM_TO_UNKNOWN:{
		NormalIMBase *base = new NormalIMBase(packet->getBodyData(), packet->getBodyLength());		
		base->parseData();
		switch(base->getNormalIMType())
		{
		case QQ_IM_NORMAL_TEXT:{
			ReceivedNormalIM * received = new ReceivedNormalIM();
			received->setNormalIMBase(base);
			received->parseData();
			const QQFriend *frd = user->getFriendList().getFriend(received->getSender());
			if(frd==NULL){
				QQFriend f(received->getSender(),received->getSenderFace());
				f.setGroupIndex(EvaUser::getAnonymousIndex());
				user->getFriendList().addFriend(f);
				user->saveGroupedBuddyList();
				emit addAnonymous(received->getSender(),received->getSenderFace());
			}else	if(frd->getGroupIndex() == EvaUser::getBlackIndex()){
					delete received;
					delete packet;
					return;
				}
				
			user->getFriendList().updateFriendIP(packet->getSender(), packet->getSenderIP());
			user->getFriendList().updateFriendPort(packet->getSender(), packet->getSenderPort());
			user->getFriendList().updateFriendFileSessionKey(packet->getSender(),received->getBuddyFileSessionKey());
			QString msg = codec->toUnicode(received->getMessage().c_str());
			QDateTime time;
			time.setTime_t(received->getSendTime());
			
			int sender = received->getSender();
			bool isNormal = received->isNormalReply();
			char fontSize = received->getFontSize();
			bool u = received->isUnderline();
			bool i = received->isItalic();
			bool b = received->isBold();
			char blue = received->getBlue();
			char green = received->getGreen();
			char red = received->getRed();
			QString sNick = codec->toUnicode(user->getFriendList().getFriend(sender)->getNick().c_str());
			QString rNick = codec->toUnicode(user->getDetails().at(ContactInfo::Info_nick).c_str());
			user->getSetting()->saveMessage(sender, sender, sNick, user->getQQ(), rNick, 
						isNormal, msg, time, fontSize, u, i, b, blue, green, red);
						
			emit txtMessage(sender, isNormal, msg, time, fontSize, 
					u, i, b, blue, green, red);
			delete received;
			}
			break;
		default:
			printf("Got a non-text msg, can't process it, ignore it\n");
		}
		delete base;
		}
		break;
	case QQ_RECV_IM_SYS_MESSAGE:{
		ReceivedSystemIM *sys = new ReceivedSystemIM(packet->getBodyData(), packet->getBodyLength());		
		switch(sys->getSystemIMType())
		{
		case QQ_RECV_IM_KICK_OUT:
			printf("this account has logged in somewhere, you are kicked out!\n");
			if(timer->isActive())
				timer->stop();
			connecter->stop();
			emit kickedOut(codec->toUnicode(sys->getMessage().c_str()));
			break;
		default:
			printf("Got a system msg: %s\n", sys->getMessage().c_str());
		}
		delete sys;
		}
		break;
	case QQ_RECV_IM_QUN_IM:
	case QQ_RECV_IM_TEMP_QUN_IM:
	case QQ_RECV_IM_UNKNOWN_QUN_IM:{
		ReceivedQunIM *im = new ReceivedQunIM(packet->getIMType(), packet->getBodyData(), packet->getBodyLength());
		Qun *qun = user->getQunList()->getQun(packet->getSender());
		if(!qun){
			Qun q(packet->getSender());
			user->getQunList()->add(q);
			doRequestQunInfo(packet->getSender());
			qun = user->getQunList()->getQun(packet->getSender());
			emit qunRequestUpdateDisplay();
		}else if( im->getVersionID() != qun->getDetails().getVersionID())
			doRequestQunInfo(packet->getSender());
		if(qun->getMessageType() == Qun::Reject){
			delete im;
			return;
		}
		if(im->getSenderQQ() == user->getQQ()){
			delete im;
			return;
		}
		QString msg = codec->toUnicode(im->getMessage().c_str());
		QDateTime time;
		time.setTime_t(im->getSentTime());
		// we cannot use  im->getQunID() to get qun id, because it's only for tempory qun's id
		int qunId = packet->getSender();
		int sender = im->getSenderQQ();
		char fontSize = im->getFontSize();
		bool u = im->isUnderline();
		bool i = im->isItalic();
		bool b = im->isBold();
		char blue = im->getBlue();
		char green = im->getGreen();
		char red = im->getRed();
		
		qun = user->getQunList()->getQun(qunId);
		QString qName = "";
		QString sNick = QString::number(sender);
		if(qun){
			QunInfo info = qun->getDetails();
			qName = codec->toUnicode(info.getName().c_str());
			const FriendItem *item = qun->getMemberDetails(sender);
			if(item)
				sNick = codec->toUnicode(item->getNick().c_str());
		}
		QString rNick = codec->toUnicode(user->getDetails().at(ContactInfo::Info_nick).c_str());
		user->getSetting()->saveMessage(qunId,  sender, sNick, user->getQQ(), rNick,
					true, msg, time, fontSize, u, i, b, blue, green, red, true);
		if(qun->getMessageType() != Qun::RecordOnly)
			emit qunTxtMessage(qunId, sender, msg, time, fontSize, u, i, b, blue, green, red);

		delete im;
		}
		break;
	case QQ_RECV_IM_CREATE_QUN:
	case QQ_RECV_IM_ADDED_TO_QUN:
	case QQ_RECV_IM_DELETED_FROM_QUN:// these three type of notifications has no messages
	case QQ_RECV_IM_REQUEST_JOIN_QUN:
	case QQ_RECV_IM_APPROVE_JOIN_QUN:
	case QQ_RECV_IM_REJECT_JOIN_QUN:{
		ReceivedQunIMJoinRequest *join = new ReceivedQunIMJoinRequest(packet->getBodyData(), packet->getBodyLength());
		QString  msg = codec->toUnicode(join->getMessage().c_str());
		user->getSetting()->saveSysMessage( packet->getIMType(), join->getType(), join->getSender(), join->getExtID(), 
						msg , packet->getSender());
		
		if( packet->getIMType()== QQ_RECV_IM_APPROVE_JOIN_QUN || packet->getIMType()== QQ_RECV_IM_ADDED_TO_QUN){	
			user->getQunList()->add(Qun(packet->getSender()));
			user->saveQunList();
			emit qunRequestUpdateDisplay();
			doRequestQunInfo(packet->getSender());
		}
		
		if( packet->getIMType()== QQ_RECV_IM_DELETED_FROM_QUN){
			user->getQunList()->remove(packet->getSender());
			user->saveQunList();
			emit qunRequestUpdateDisplay();
		}
		emit qunSystemMessageRequest(join->getSender(), msg);
		delete join;
		}
		break;
	case QQ_RECV_IM_SIGNATURE_CHANGED:{
		SignatureChangedPacket *sig = new SignatureChangedPacket(packet->getBodyData(), packet->getBodyLength());
		user->getFriendList().setSignature(sig->getQQ(), sig->getSignature(), sig->getTime());
		user->saveGroupedBuddyList();
		QString sigMsg = codec->toUnicode(sig->getSignature().c_str());
		QDateTime time;
		time.setTime_t(sig->getTime());
		emit friendSignatureChanged(sig->getQQ(), time, sigMsg);
		break;
		}
	default:{
		printf("Unknow IM Type: 0x%2x\n", packet->getIMType());
		printf("sender: %d, receiver: %d, sender IP: %s, sender port: %d\n", packet->getSender(), packet->getReceiver(),
								QHostAddress(packet->getSenderIP()).toString().ascii(), packet->getSenderPort());
		short version = packet->getVersion();
		short command = packet->getCommand();
		short sequence = packet->getSequence();
		short bodyLength = packet->getLength();
		printf("version:0x%4x, command: 0x%4x, sequence: 0x%4x\n", version, command, sequence);
		printf("after InPacket headr(7(UDP) or 9(TCP) bytes) plus ReceiveIMPacket header(20 bytes):\n");
		for(int i=0; i<bodyLength; i++){
			if(!(i%8)) printf("\n%d: ",i);
			char t = packet->getBody()[i];
			printf("%2x ", (uint8_t)t);
		}
		printf("\n============================\n");  
		}
	}
	delete packet;
}

void EvaPacketManager::doGetGroups( )
{
	connecter->append(new GroupNameOpPacket(QQ_DOWNLOAD_GROUP_NAME));
}

void EvaPacketManager::doUploadGroups()
{
	GroupNameOpPacket *packet = new GroupNameOpPacket(QQ_UPLOAD_GROUP_NAME);
	packet->setGroups(user->getGroupNames());
	connecter->append(packet);
}

void EvaPacketManager::processGroupNameOp( const InPacket * in )
{
	GroupNameOpReplyPacket *packet = new GroupNameOpReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	if(packet->isDownloadReply()){
		std::list<std::string>::iterator iter;
		std::list<std::string> names = packet->getGroupNames();
		user->clearGroupNames(); // note that the first group won't be deleted
		for(iter = names.begin(); iter != names.end(); ++iter){
			user->newGroup(*iter);
		}
		doGetGroupedFriends();
	}else{
		std::map<int, QQFriend> srcList = user->getFriendList().getFriendList();
		std::map<int, QQFriend>::iterator iter;
		std::map<int, int> destList;
		for(iter = srcList.begin(); iter!= srcList.end(); ++iter){
			if((iter->second).getGroupIndex() != user->getAnonymousIndex() &&
				(iter->second).getGroupIndex() != user->getBlackIndex()){
				destList[(iter->second).getQQ()] = (iter->second).getGroupIndex();
			}
		}
		UploadGroupFriendPacket *packet = new UploadGroupFriendPacket();
		packet->setGroupedFriends(destList);
		connecter->append(packet);
	}
	delete packet;
}

void EvaPacketManager::doGetGroupedFriends( )
{
	connecter->append(new DownloadGroupFriendPacket());
}

void EvaPacketManager::processDownloadGroupFriendReply( const InPacket * in )
{
	DownloadGroupFriendReplyPacket *packet = new DownloadGroupFriendReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	std::list<DownloadFriendEntry> friends = packet->getGroupedFriends();
	std::list<DownloadFriendEntry>::iterator iter;
	for(iter = friends.begin(); iter!= friends.end(); ++iter){
		if(!iter->isQun()){
			user->getFriendList().updateFriendGroupIndex(iter->getQQ(), iter->getGroupID());
		}else{
			Qun q(iter->getQQ());
			user->getQunList()->add(q);
		}
	}
	
	int nextID = packet->getNextStartID();
	if(nextID != 0x0000){
		connecter->append(new DownloadGroupFriendPacket(nextID));
	}else{
		emit friendGroupsReady();
		QunList *qunList = user->getQunList();
		if(qunList && qunList->numQuns()){
			doRequestQunInfo(qunList->getQunList().begin()->getQunID());
		}
	}
	delete packet;
}

void EvaPacketManager::processUploadGroupFriendReply(const InPacket *in)
{
	UploadGroupFriendReplyPacket *packet = new UploadGroupFriendReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	if(packet->uploadOk()) 
		emit friendGroupsUploadReady(true);
	else
		emit friendGroupsUploadReady(false);
	
	delete packet;
}

void EvaPacketManager::doDeleteBuddy( const int id )
{
	if(deletingBuddyQQ)
		return;
	deletingBuddyQQ = id;
	DeleteFriendPacket *packet = new DeleteFriendPacket(id);
	saveBuddyQQ(id, packet->getSequence());
	connecter->append(packet);
}

void EvaPacketManager::processDeleteFriendReply( const InPacket * in )
{
	DeleteFriendReplyPacket *packet = new DeleteFriendReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	if(packet->isDeleted()){
		user->getFriendList().deleteFriend(deletingBuddyQQ);
		user->saveGroupedBuddyList();
	}
	deletingBuddyQQ = 0;
	int id = getSavedBuddyQQ(packet->getSequence());
	if(id==-1) {
		delete packet;
		return;
	}
	removeSequence(packet->getSequence());
	emit deleteBuddyReady(id, packet->isDeleted());	
	delete packet;
}

void EvaPacketManager::doAddBuddy( const int id )
{
	if(addingBuddyQQ) {
		emit addingBuddy(addingBuddyQQ);
		return;
	}
	addingBuddyQQ = id;
	connecter->append(new AddFriendPacket(id));
}

void EvaPacketManager::processAddFriendReply( const InPacket * in )
{
	AddFriendReplyPacket *packet = new AddFriendReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	switch(packet->getReplyCode()){
	case QQ_AUTH_NO_AUTH:{
		QQFriend frd(addingBuddyQQ, 0);
		user->getFriendList().addFriend(frd);
		addingBuddyQQ = 0;
		emit addBuddyReady();
		}
		break;
	case QQ_AUTH_NEED_AUTH:
		addingBuddyQQ = 0;
		emit addBuddyNeedAuth();
		break;
	case QQ_AUTH_NO_ADD:
		addingBuddyQQ = 0;
		emit addBuddyRejected();
		break;
	}
	delete packet;	
}

void EvaPacketManager::doAddAuthBuddy( const int id, const QString &message)
{
	AddFriendAuthPacket *packet = new AddFriendAuthPacket(id, QQ_MY_AUTH_REQUEST);
	QCString msg = codec->fromUnicode(message);
	packet->setMessage(msg.data());
	connecter->append(packet);
}

void EvaPacketManager::doApproveBuddy( const int id)
{
	AddFriendAuthPacket *packet = new AddFriendAuthPacket(id, QQ_MY_AUTH_APPROVE);
	connecter->append(packet);
}

void EvaPacketManager::doRejectBuddy( const int id , const QString &message)
{
	AddFriendAuthPacket *packet = new AddFriendAuthPacket(id, QQ_MY_AUTH_REJECT);
	QCString msg = codec->fromUnicode(message);
	packet->setMessage(msg.data());
	connecter->append(packet);
}

void EvaPacketManager::processAddFriendAuthReply( const InPacket * in )
{
	AddFriendAuthReplyPacket *packet = new AddFriendAuthReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	emit addBuddySentToServer(packet->isSentOK());
	delete packet;
}

void EvaPacketManager::processSystemNotification( const InPacket * in )
{
	SystemNotificationPacket *packet = new SystemNotificationPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	QString msg = codec->toUnicode(packet->getMessage().c_str());
	
	user->getSetting()->saveSysMessage( SYSTEM_MESSAGE_NORMAL, packet->getType(), packet->getFromQQ(), packet->getMyQQ(), msg);
	switch(packet->getType()){
	case QQ_MSG_SYS_BEING_ADDED:
		emit systemMeBeenAdded( packet->getFromQQ());
		break;       
	case QQ_MSG_SYS_ADD_FRIEND_REQUEST:
		emit systemAddMeRequest(packet->getFromQQ(), msg);
		break;
	case QQ_MSG_SYS_ADD_FRIEND_APPROVED:{
		QQFriend frd(packet->getFromQQ(), 0);
		user->getFriendList().addFriend(frd);
		emit systemAddRequestApproved(packet->getFromQQ());
		}
		break;
	case QQ_MSG_SYS_ADD_FRIEND_REJECTED:
		emit systemAddRequestRejected(packet->getFromQQ(), msg);
		break;
	default:
		emit systemNotification(packet->getFromQQ(), msg);	
	}
	delete packet;
}

void EvaPacketManager::doModifyDetails(QStringList info, QString oldPwd, QString newPwd)
{
	std::vector<std::string> result;
	for(uint i=0; i< info.count(); i++){
		result.push_back((codec->fromUnicode(info[i])).data());
	}
	changingDetails.setDetails(result);
	ModifyInfoPacket *packet = new ModifyInfoPacket(changingDetails);
	if(oldPwd != QString::null && newPwd != QString::null){
		std::string o, n;
		o = codec->fromUnicode(oldPwd).data();
		n = codec->fromUnicode(newPwd).data();
		packet->setPassword(o);
		packet->setNewPassword(n);
	}
	connecter->append(packet);
}

void EvaPacketManager::processModifyInfoReply(const InPacket *in)
{
	ModifyInfoReplyPacket *packet = new ModifyInfoReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	if(packet->isAccepted()){
		user->setDetails(changingDetails);
		user->saveGroupedBuddyList();
		emit myInfoReady();
		emit modifyInfo(true);
	}else
		emit modifyInfo(false);
	delete packet;
}

QStringList EvaPacketManager::convertDetails(const ContactInfo &info)
{
	QStringList result;
	for(uint i=0; i< info.count(); i++){
		result.append(codec->toUnicode(info.at(i).c_str()));
	}
	return result;
}

void EvaPacketManager::doSearchUsers( const bool isSearchAll, const QString page, const QString id, 
				const QString nick, const QString email, const bool match )
{
	SearchUserPacket *packet = new SearchUserPacket();
	if(!isSearchAll){
		packet->setSearchType(QQ_SEARCH_CUSTOM);
		packet->setPage(codec->fromUnicode(page).data());
		packet->setQQ(codec->fromUnicode(id).data());
		packet->setNick(codec->fromUnicode(nick).data());
		packet->setEmail(codec->fromUnicode(email).data());		
		packet->setMatchEntireString(match);
	}
        connecter->append(packet);
}

void EvaPacketManager::processSearchUserReply( const InPacket * in )
{
	SearchUserReplyPacket *packet = new SearchUserReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}

	emit searchUsersReady(packet->isFinished(), packet->getUsers());
	delete packet;
}

void EvaPacketManager::doDeleteMeFrom( const int id )
{
	DeleteMePacket *packet = new DeleteMePacket(id);
	connecter->append(packet);
}

void EvaPacketManager::processDeleteMeReply( const InPacket * in )
{
	DeleteMeReplyPacket *packet = new DeleteMeReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	emit deleteMeReady(packet->isDeleted());
	delete packet;
}

void EvaPacketManager::processQunReply( const InPacket * in )
{
	QunReplyPacket *packet = new QunReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	switch(packet->getQunCommand()){
	case QQ_QUN_CMD_SEND_IM:
	case QQ_QUN_CMD_SEND_IM_EX:
		emit qunSentMessageResult(packet->getQunID() ,packet->isReplyOK(), codec->toUnicode(packet->getErrorMessage().c_str()));
		break;
	case QQ_QUN_CMD_SEND_TEMP_QUN_IM:
		break;
	case QQ_QUN_CMD_CREATE_QUN:
		if(packet->isReplyOK()){
			Qun q(packet->getQunID());
			user->getQunList()->add(q);
			doRequestQunInfo(packet->getQunID());
			emit qunCreateDone(packet->getQunID());
			connecter->append(new QunActivePacket(packet->getQunID()));
			emit qunRequestUpdateDisplay();
		}else
			emit qunCreateFailed(codec->toUnicode(packet->getErrorMessage().c_str()));
		break;
	case QQ_QUN_CMD_CREATE_TEMP_QUN:
		break;
	case QQ_QUN_CMD_ACTIVATE_QUN:
		if(!packet->isReplyOK())
			emit qunActiveQunFailed(codec->toUnicode(packet->getErrorMessage().c_str()));
		break;
	case QQ_QUN_CMD_MODIFY_MEMBER:
		if(packet->isReplyOK())
			doRequestQunInfo(packet->getQunID());
		emit qunModifyQunMembersReply(packet->getQunID(), packet->isReplyOK(), codec->toUnicode(packet->getErrorMessage().c_str()));
		break;
	case QQ_QUN_CMD_GET_QUN_INFO:{
		if(!packet->isReplyOK()){
			// note that if comes here, the packet->getQunID() won't get the right id, only error message is ok
			emit qunInfomationReady(processQunID, packet->isReplyOK(), codec->toUnicode(packet->getErrorMessage().c_str()));
			switch(packet->getReplyCode()){
			case 3: // qun has been dismissed
				user->getQunList()->remove(processQunID);
				user->saveQunList();
				emit qunRequestUpdateDisplay();
				break;
			default:break;
			}
			processQunID = 0;
			return;
		}

		QunInfo info = packet->getQunInfo();
		user->getQunList()->setDetails(info);
		user->getQunList()->setMemberArgs(info.getQunID(), packet->getMemberList());
		emit qunInfomationReady(info.getQunID(), packet->isReplyOK(), codec->toUnicode(packet->getErrorMessage().c_str()));
		
		std::map<int, QunMember>::iterator iter;
		std::map<int, QunMember> lst = packet->getMemberList();
		std::list<int> toSend;
		int i=0;
		qunMemberInfoFinished = false;

		for(iter= lst.begin(); iter != lst.end(); ++iter){
			if(i==30){
				doRequestQunMemberInfo(info.getQunID(), toSend);
				toSend.clear();
				i = 0;
			}
			toSend.push_back(iter->second.qqNum);
			i++;
		}
		if(toSend.size())
			doRequestQunMemberInfo(info.getQunID(), toSend);

		qunMemberInfoFinished = true;
		processQunID = 0;
		std::list<Qun>::iterator qunIter;
		std::list<Qun> list = user->getQunList()->getQunList();
		for(qunIter = list.begin(); qunIter != list.end(); ++qunIter){
			QunInfo info = qunIter->getDetails();printf("qun: %d\n", qunIter->getQunID());
			if(info.getExtID() == 0){
				doRequestQunInfo(qunIter->getQunID());
				break;
			}
		}
 		}
		break;
	case QQ_QUN_CMD_EXIT_QUN:
		emit qunExitReply(packet->getQunID(), packet->isReplyOK(), codec->toUnicode(packet->getErrorMessage().c_str()));
		if(packet->isReplyOK()){
			user->getQunList()->remove(packet->getQunID());
			user->saveQunList();
			emit qunRequestUpdateDisplay();
		}
		break;
	case QQ_QUN_CMD_GET_MEMBER_INFO:{
			user->getQunList()->setMembers(packet->getQunID(), packet->getMemberInfoList());
			if(!qunMemberInfoFinished) break;
			user->saveQunList();
			emit qunMemberInfoReady(packet->getQunID());
		}
		break;
	case QQ_QUN_CMD_GET_ONLINE_MEMBER:{
		user->getQunList()->setOnlineMembers(packet->getQunID(), packet->getQQNumberList());
		}
		emit qunOnlineListReady(packet->getQunID());
		break;
	case QQ_QUN_CMD_JOIN_QUN:
		switch(packet->getJoinReply()){
		case QQ_QUN_JOIN_OK:{
			user->getQunList()->add(Qun(packet->getQunID()));
			emit qunJoinReplyOK(packet->getQunID());
			emit qunRequestUpdateDisplay();
			doRequestQunInfo(packet->getQunID());
			}
			break;
		case QQ_QUN_JOIN_NEED_AUTH:
			emit qunJoinReplyNeedAuth(packet->getQunID());
			break;
		case QQ_QUN_JOIN_DENIED:
			emit qunJoinReplyDenied(packet->getQunID());
			break;
		default:
			printf("comes here:%2x\n", (unsigned char)(packet->getJoinReply()));
			printf("error:%s\n",packet->getErrorMessage().c_str());
		}
		break;
	case QQ_QUN_CMD_JOIN_QUN_AUTH:
		emit qunJoinAuthReply(packet->getQunID());
		break;
	case QQ_QUN_CMD_MODIFY_QUN_INFO:
		if(packet->isReplyOK())
			doRequestQunInfo(packet->getQunID());
		emit qunModifyInfoReply(packet->getQunID(), packet->isReplyOK(), codec->toUnicode(packet->getErrorMessage().c_str()));
		break;
	case QQ_QUN_CMD_SEARCH_QUN:
		emit qunSearchReady(packet->getQunInfoList(), codec->toUnicode(packet->getErrorMessage().c_str()));
		break;
	case QQ_QUN_CMD_GET_TEMP_QUN_INFO:
		break;
	case QQ_QUN_CMD_EXIT_TEMP_QUN:
		break;
	case QQ_QUN_CMD_GET_TEMP_QUN_MEMBERS:
		break;
	case QQ_QUN_CMD_MODIFY_CARD:
		emit qunModifyQunCardReply(packet->getQunID(), packet->isReplyOK(), packet->getTargetQQ(),
							 codec->toUnicode(packet->getErrorMessage().c_str()));
		break;
	case QQ_QUN_CMD_REQUEST_CARD:
		if(packet->isReplyOK() && (packet->getTargetQQ() == user->getQQ()) )
			user->getQunList()->setMyQunCardInfo(packet->getQunID(), packet->getRealName(), packet->getGender(),
						packet->getPhone(), packet->getEmail(), packet->getMemo());
		emit qunRequestQunCardReply(packet->getQunID(), packet->isReplyOK(), packet->getTargetQQ(),
					codec->toUnicode(packet->getRealName().c_str()), packet->getGender(),
					codec->toUnicode(packet->getPhone().c_str()),codec->toUnicode(packet->getEmail().c_str()),
					codec->toUnicode(packet->getMemo().c_str()),codec->toUnicode(packet->getErrorMessage().c_str()));
		break;
	case QQ_QUN_CMD_ADMIN:
		if(packet->isReplyOK())
			doRequestQunInfo(packet->getQunID());
		emit qunSetAdminReply(packet->getQunID(), packet->isReplyOK(), packet->getTargetQQ(),
					(packet->getOpCode() == QQ_QUN_SET_ADMIN), codec->toUnicode(packet->getErrorMessage().c_str()));
		break;
	case QQ_QUN_CMD_TRANSFER:
		if(packet->isReplyOK())
			doRequestQunInfo(packet->getQunID());
		emit qunTransferReply(packet->getQunID(), packet->isReplyOK(), packet->getTargetQQ(),
						  codec->toUnicode(packet->getErrorMessage().c_str()));
		break;
	default:
		printf("Unknown qun operation reply\n");
	}
	delete packet;
}

void EvaPacketManager::doRequestQunInfo( const int id )  // note that the id should be the internal Qun ID
{
	if(processQunID) return;
	processQunID = id;
	connecter->append(new QunGetInfoPacket(id));
}

void EvaPacketManager::doRequestQunMemberInfo( const int id , const std::list<int> &l)
{
	QunGetMemberInfoPacket *packet = new QunGetMemberInfoPacket(id);
	packet->setMemberList(l);
	connecter->append(packet);
}

void EvaPacketManager::doRequestQunOnlineMembers( const int id )
{
	connecter->append(new QunGetOnlineMemberPacket(id));
}

void EvaPacketManager::doSendQunMessage( const int receiver, QString & message, const char fontSize, 
					const bool u, const bool i, const bool b, 
					const char blue, const char green, const char red )
{
	QString rNick = QString::number(receiver);
	const Qun *qun = user->getQunList()->getQun(receiver);
	if(qun){
		QunInfo info = qun->getDetails();
		rNick = codec->toUnicode(info.getName().c_str());
	}
	QString sNick = codec->toUnicode(user->getDetails().at(ContactInfo::Info_nick).c_str());
	QDateTime time = QDateTime::currentDateTime(Qt::LocalTime);	
	user->getSetting()->saveMessage(receiver,  user->getQQ(), sNick, receiver, rNick,
				true, message, time, fontSize, u, i, b, blue, green, red, true);
	
	QunSendIMExPacket *packet = new QunSendIMExPacket(receiver);
	packet->setFontSize(fontSize);
	packet->setUnderline(u); 
	packet->setItalic(i);
	packet->setBold(b);
	packet->setBlue(blue);
	packet->setGreen(green);
	packet->setRed(red);
	QCString str = codec->fromUnicode(message);
	packet->setMessage(str.data());
	connecter->append(packet);
}

void EvaPacketManager::doSearchQun( const int extID )
{
	QunSearchPacket *packet = new QunSearchPacket();
	packet->setExtID(extID);
	connecter->append(packet);
}

void EvaPacketManager::doJoinQun( const int qunID )
{
	QunJoinPacket *packet = new QunJoinPacket(qunID);
	connecter->append(packet);
}

void EvaPacketManager::doJoinQunAuth( const int qunID , const QString &message)
{
	QunAuthPacket *packet = new QunAuthPacket(qunID, QQ_QUN_AUTH_REQUEST);
	std::string msg = (codec->fromUnicode(message)).data();
	packet->setMessage(msg);
	connecter->append(packet);
}

void EvaPacketManager::doApproveQun( const int id, const int qunID)
{
	QunAuthPacket *packet = new QunAuthPacket(qunID, QQ_QUN_AUTH_APPROVE);
	packet->setReceiver(id);
	connecter->append(packet);
}

void EvaPacketManager::doRejectQun( const int id, const int qunID, const QString & message)
{	
	QunAuthPacket *packet = new QunAuthPacket(qunID, QQ_QUN_AUTH_REJECT);
	packet->setReceiver(id);
	std::string msg = (codec->fromUnicode(message)).data();
	packet->setMessage(msg);
	connecter->append(packet);
}

void EvaPacketManager::doGetAllLevels( )
{
	std::list<int> list;
	list.push_back(user->getQQ());
	
	std::list<QQFriend> friends = user->getFriendList().getAllFriends();
	std::list<QQFriend>::iterator iter;
	
	int i = 0;
	for(iter = friends.begin(); iter!=friends.end(); ++iter){
		list.push_back(iter->getQQ());
		i++;
		if(i==70){
			EvaGetLevelPacket *packet = new EvaGetLevelPacket(list);
			connecter->append(packet);
			list.clear();
			i=0;
		}
	}

	if(list.size()){
		EvaGetLevelPacket *packet = new EvaGetLevelPacket(list);
		connecter->append(packet);
	}
}

void EvaPacketManager::requestFriendLevel(const int id)
{
	std::list<int> list;
	list.push_back(id);
	EvaGetLevelPacket *packet = new EvaGetLevelPacket(list);
	connecter->append(packet);
}

void EvaPacketManager::processGetLevelReply( const InPacket * in )
{
	EvaGetLevelReplyPacket *packet = new EvaGetLevelReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	
	std::list<LevelUserItem> friends = packet->getLevelList();
	std::list<LevelUserItem>::iterator iter;
	for(iter = friends.begin(); iter != friends.end(); ++iter){
		if(iter->qqNum == user->getQQ()){
			user->setOnlineTime(iter->onlineTime);
			user->setLevel(iter->level);
			user->setHoursToLevelUp(iter->timeRemainder);
		}else
			user->getFriendList().updateFriendLevel(iter->qqNum, iter->onlineTime, iter->level, iter->timeRemainder);
		
	}
	delete packet;
}

void EvaPacketManager::doModifyQunInfo( const int id, unsigned char auth, unsigned short cate, 
					QString name, QString notice, QString description )
{
	std::string qunName = (codec->fromUnicode(name)).data();
	std::string qunNotice = (codec->fromUnicode(notice)).data();
	std::string qunDescription = (codec->fromUnicode(description)).data();
	
	QunInfo info;
	info.setQunID(id);
	info.setAuthType(auth);
	info.setCategory(cate);
	info.setName(qunName);
	info.setNotice(qunNotice);
	info.setDescription(qunDescription);
	connecter->append(new QunModifyPacket(info));
}

void EvaPacketManager::doModifyQunCard(const int id,  const int qqID, QString name, unsigned char gender, 
				QString phone, QString email, QString memo )
{
	QunModifyCardPacket *packet = new QunModifyCardPacket(id, qqID);
	
	std::string cardName = codec->fromUnicode(name).data(); 
	std::string cardPhone = codec->fromUnicode(phone).data();
	std::string cardEmail = codec->fromUnicode(email).data();
	std::string cardMemo = codec->fromUnicode(memo).data();
	
	packet->setName(cardName);
	packet->setGender(gender);
	packet->setPhone(cardPhone);
	packet->setEmail(cardEmail);
	packet->setMemo(cardMemo);
	connecter->append(packet);
}

void EvaPacketManager::doQunSetAdmin( const int id, const int qq, const bool isSetAdmin )
{
	connecter->append(new QunAdminOpPacket(id, qq, isSetAdmin));
}

void EvaPacketManager::doQunTransfer( const int id, const int qq )
{
	connecter->append(new QunTransferPacket(id, qq));
}

void EvaPacketManager::doModifyQunMembers( const int id, const std::list< int > members, const bool isAdd )
{
	QunModifyMemberPacket *packet = new QunModifyMemberPacket(id, isAdd);
	packet->setMembers(members);
	connecter->append(packet);
}

void EvaPacketManager::processRequestKeyReply( const InPacket * in )
{
	EvaRequestKeyReplyPacket *packet = new EvaRequestKeyReplyPacket();
	packet->setInPacket(in);
	packet->parse();
	delete packet;
	if(packet->getKeyType() == QQ_REQUEST_FILE_AGENT_KEY){
		user->loginManager()->finishedCommand(QQ_CMD_REQUEST_KEY);
	}
	
}

void EvaPacketManager::doRequestQunCard( const int id, const int qq )
{
	connecter->append(new QunRequestCardPacket(id, qq));
}

void EvaPacketManager::doQunExit( const int id )
{
	connecter->append(new QunExitPacket(id));
}

void EvaPacketManager::doQunCreate( const QString & name, const unsigned short category, const unsigned char auth, 
				const QString & notice, const QString & description, const std::list< int > & members )
{
	QCString _name = codec->fromUnicode(name);
	QCString _notice = codec->fromUnicode(notice);
	QCString _description = codec->fromUnicode(description);
	
	QunCreatePacket *packet = new QunCreatePacket(_name.data(), category, auth);
	packet->setNotice(_notice.data());
	packet->setDescription(_description.data());
	packet->setMembers(members);
	connecter->append(packet);
}

void EvaPacketManager::doRequestExtraInfo( )
{
	connecter->append(new RequestExtraInfoPacket());
}

void EvaPacketManager::processRequestExtraInfoReply(const InPacket *in)
{
	RequestExtraInfoReplyPacket *packet = new RequestExtraInfoReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	if(packet->getReplyCode() != 1){
		delete packet;
		return;
	}
	std::map<int, unsigned short> members = packet->getMembers();
	std::map<int, unsigned short>::iterator iter;
	for(iter = members.begin(); iter!= members.end(); ++iter){
		if(iter->first == user->getQQ())
			user->setExtraInfo(iter->second);
		else
			user->getFriendList().setExtraInfo(iter->first, iter->second);
	}
	if(packet->getOffset()!=QQ_FRIEND_LIST_POSITION_END){
		connecter->append(new RequestExtraInfoPacket(packet->getOffset()));
	}else{
		emit extraInfoReady();
		doRequestSignature();
	}
	delete packet;
}

void EvaPacketManager::doModifySignature( const QString signature )
{
	SignaturePacket *packet = new SignaturePacket(QQ_SIGNATURE_MODIFY);
	std::string sig = codec->fromUnicode(signature).data();
	packet->setSignature(sig);
	connecter->append(packet);
}

void EvaPacketManager::doDeleteSignature( )
{
	connecter->append(new SignaturePacket(QQ_SIGNATURE_DELETE));
}

void EvaPacketManager::doRequestSignature( const int start)
{
	std::map<int, int> list = user->getFriendList().getMemberSignatureList(start, user->getQQ(), user->hasSignature());
	if(list.size()){
		SignaturePacket *packet = new SignaturePacket(QQ_SIGNATURE_REQUEST);
		packet->setMembers(list);
		connecter->append(packet);
	}
}

void EvaPacketManager::processSignatureReply( const InPacket * in )
{
	SignatureReplyPacket *packet = new SignatureReplyPacket();
	packet->setInPacket(in);
	if(!packet->parse()){
		delete packet;
		return;
	}
	
	switch(packet->getType()){
	case QQ_SIGNATURE_MODIFY:
		if(packet->isChangeAccepted())
			doRequestSignature(user->getQQ());
		emit signatureModifyReply(packet->isChangeAccepted());
		break;
	case QQ_SIGNATURE_DELETE:
		emit signatureDeleteReply(packet->isChangeAccepted());
		if(packet->isChangeAccepted()){
			user->setSignature("", 0);
		}
		break;
	case QQ_SIGNATURE_REQUEST:{
		std::map<int, SignatureElement> members = packet->getMembers();
		std::map<int, SignatureElement>::iterator iter;
		for(iter = members.begin(); iter!= members.end(); ++iter){
			if(iter->first == user->getQQ())
				user->setSignature(iter->second.signature, iter->second.lastModifyTime);
			else
				user->getFriendList().setSignature(iter->first, iter->second.signature, iter->second.lastModifyTime);
		}
		user->saveGroupedBuddyList();
		doRequestSignature(packet->nextStartID());
		}
		break;
	}
	delete packet;
}

void EvaPacketManager::lastLoginStep()
{	
	doGetAllLevels();
	doRequestExtraInfo();
}




