/***************************************************************************
 *   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 "evaimreceive.h"
#include "evadefines.h"
#include "evautil.h"
#include <string.h>
#include <arpa/inet.h>


ReceiveIMPacket::ReceiveIMPacket(unsigned char *buf, const int len)
	: InPacket(buf, len),
	bodyOffset(0)
{
}   

ReceiveIMPacket::ReceiveIMPacket(const ReceiveIMPacket &rhs)
	: InPacket(rhs)
{
	memcpy(replyKey, rhs.getReplyKey(), REPLY_KEY_LENGTH);
	sender = rhs.getSender();
	receiver = rhs.getReceiver();
	sequence = rhs.getSequence();
	senderIP = rhs.getSenderIP();
	senderPort = rhs.getSenderPort();
	type = rhs.getIMType();
	
	bodyOffset = rhs.getLength() - rhs.getBodyLength();
}

std::string ReceiveIMPacket::convertToShow(const std::string &src)
{
	std::string converted = "";
	EvaUtil util;
	for(uint i=0; i<src.length(); i++){
		if(src[i]==0x14){
			converted+=util.smileyToText(src[++i]);
			converted+=' ';
		}else
			converted+=src[i];
	}
	return converted;
}

ReceiveIMPacket &ReceiveIMPacket::operator=(const ReceiveIMPacket &rhs)
{
	*((InPacket *)this) = (InPacket)rhs;
	memcpy(replyKey, rhs.getReplyKey(), REPLY_KEY_LENGTH);
	sender = rhs.getSender();
	receiver = rhs.getReceiver();
	sequence = rhs.getSequence();
	senderIP = rhs.getSenderIP();
	senderPort = rhs.getSenderPort();
	type = rhs.getIMType();
	
	bodyOffset = rhs.getLength() - rhs.getBodyLength();
        return *this;
}

void ReceiveIMPacket::parseBody()
{
	if(bodyLength < 16){
		printf("message too short, just chuck it\n");  
		bodyOffset = -1; // means error occurred
		return;
	}
	memcpy(replyKey, decryptedBuf, REPLY_KEY_LENGTH);
	bodyOffset = readHeader(decryptedBuf);
// 	if(bodyOffset==bodyLength) {
// 		return;
// 	}    
// 	switch(header.type){
// 		case QQ_RECV_IM_TO_BUDDY:
// 		case QQ_RECV_IM_TO_UNKNOWN:
// 			parseNormalIM(bodyBuf+pos, bodyLength-pos);
// 			break;
// 		case QQ_RECV_IM_SYS_MESSAGE:
// 			parseSystemMessage(bodyBuf+pos, bodyLength-pos);
// 			break;
// 		default:
// 			return; 
// 	}
}

int ReceiveIMPacket::readHeader(const unsigned char *buf)
{
	int pos=0;	
	int tmp4;
	memcpy(&tmp4, buf, 4);
	sender = ntohl(tmp4);
	pos+=4;
	
	memcpy(&tmp4, buf+pos, 4);
	receiver = ntohl(tmp4);
	pos+=4;
		
	memcpy(&tmp4, buf+pos, 4);
	intSequence = ntohl(tmp4);
	pos+=4;

	memcpy(&tmp4, buf+pos, 4);
	senderIP = ntohl(tmp4);
	pos+=4;
		
	short tmp2;
	memcpy(&tmp2, buf+pos, 2);
	senderPort = ntohs(tmp2);
	pos+=2;
		
	memcpy(&tmp2, buf+pos, 2);
	type = ntohs(tmp2);
	pos+=2;	
	return pos;
}

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

NormalIMBase::NormalIMBase(const unsigned char *buf, const int len)
{
	bodyBuf = (unsigned char *)malloc(len * sizeof(unsigned char));
	bodyLength = len;
	memcpy(bodyBuf, buf, len);
}

NormalIMBase::NormalIMBase(const NormalIMBase &rhs)
{
	*this = rhs;
}

NormalIMBase::~NormalIMBase()
{
	free(bodyBuf);
}

void NormalIMBase::setNormalIMBase(const NormalIMBase *base)
{
	*this = *base;	
}

void NormalIMBase::parseData()
{
	int len = readHeader(bodyBuf);
	parseContents(bodyBuf + len, bodyLength - len);
}

NormalIMBase &NormalIMBase::operator=(const NormalIMBase &rhs)
{
	bodyLength = rhs.getBodyLength();
	bodyBuf = (unsigned char *)malloc(bodyLength * sizeof(unsigned char));
	memcpy(bodyBuf, rhs.getBodyData(), bodyLength);
	
	senderVersion = rhs.getSenderVersion();
	sender = rhs.getSender();
	receiver = rhs.getReceiver();
	memcpy(fileSessionKey, rhs.getBuddyFileSessionKey(), 16);
	type = rhs.getNormalIMType();
	sequence = rhs.getSequence();
	sendTime = rhs.getSendTime();
	unknown1 = rhs.getUnknown1();
	senderFace = rhs.getSenderFace();
        return *this;
}

void NormalIMBase::parseContents(const unsigned char *, const int )
{
	//fprintf(stderr, "In NormalIMBase: buf[0]=0x%2x, len=%d\n",buf[0], len); 
}

int NormalIMBase::readHeader(const unsigned char *buf)
{
	int pos=0;
	short tmp2;
	memcpy(&tmp2, buf, 2);	
	senderVersion = ntohs(tmp2);
	pos+=2;
	
	int tmp4;
	memcpy(&tmp4, buf+pos, 4);
	sender = ntohl(tmp4);
	pos+=4;
	memcpy(&tmp4, buf+pos, 4);
	receiver = ntohl(tmp4);
	pos+=4;
	
	memcpy(fileSessionKey, buf+pos, 16);
	pos+=16;
	
	memcpy(&tmp2, buf+pos, 2);
	type = ntohs(tmp2);
	pos+=2;
	
	memcpy(&tmp2, buf+pos, 2);
	sequence = ntohs(tmp2);
	pos+=2;
	
	memcpy(&tmp4, buf+pos, 4);
	//sendTime = ntohl(tmpTime) * 1000L;
	sendTime = ntohl(tmp4);
	pos+=4;
	
	unknown1 = buf[pos++];
	senderFace = buf[pos++];
	
	return pos;
}

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

ReceivedNormalIM::ReceivedNormalIM(const unsigned char *buf, const int len)
	: NormalIMBase(buf, len)
{
}

ReceivedNormalIM::ReceivedNormalIM(const ReceivedNormalIM &rhs)
	: NormalIMBase(rhs)
{
	memcpy(unknown2, rhs.getUnknown2(), 3);
	memcpy(unknown3, rhs.getUnknown3(), 4);
	replyType = rhs.getReplyType();
	message = rhs.getMessage();
	mHasFontAttribute = rhs.hasFontAttribute();
	encoding = rhs.getEncoding();
	red = rhs.getRed();
	green = rhs.getGreen();
	blue = rhs.getBlue();
	fontSize = rhs.getFontSize();
	fontName = rhs.getFontName();
	bold = rhs.isBold();
	italic = rhs.isItalic();
	underline = rhs.isUnderline();
}

const bool ReceivedNormalIM::isNormalReply() const
{
	return replyType == QQ_IM_NORMAL_REPLY;
}

ReceivedNormalIM &ReceivedNormalIM::operator=(const ReceivedNormalIM &rhs)
{
	*((NormalIMBase *)this) = (NormalIMBase)rhs;
	memcpy(unknown2, rhs.getUnknown2(), 3);
	memcpy(unknown3, rhs.getUnknown3(), 4);
	replyType = rhs.getReplyType();
	message = rhs.getMessage();
	mHasFontAttribute = rhs.hasFontAttribute();
	encoding = rhs.getEncoding();
	red = rhs.getRed();
	green = rhs.getGreen();
	blue = rhs.getBlue();
	fontSize = rhs.getFontSize();
	fontName = rhs.getFontName();
	bold = rhs.isBold();
	italic = rhs.isItalic();
	underline = rhs.isUnderline();
        return *this;
}

void ReceivedNormalIM::parseContents(const unsigned char *buf, const int len)
{
	int pos=0;
	memcpy(unknown2, buf, 3);
        pos+=3;
	        
        mHasFontAttribute = (buf[pos++] != 0);
	memcpy(unknown3, buf+pos, 4);
	pos+=4;

        replyType = buf[pos++];
			
	int i=0;
	while( (buf[pos++]) != 0x00){
		i++;
	}
	char str[i+1];
	memcpy(str, buf+(pos-i-1), i+1);
	str[i+1]= 0x00;
	message = ReceiveIMPacket::convertToShow(str);
	
        if(mHasFontAttribute) {
		if(pos<len) {
			char fa[len-pos];
			memcpy(fa, buf+pos, len-pos);
			fontSize = fa[0] & 0x1F;
			bold = ((fa[0] & 0x20) != 0);
			italic = ((fa[0] & 0x40) != 0);
			underline = ((fa[0] & 0x80) != 0);
			red = fa[1] & 0xFF;
			green = fa[2] & 0xFF;
			blue = fa[3] & 0xFF;
			short tmp2;
			memcpy(&tmp2, fa+5, 2);
			encoding = ntohs(tmp2);
			char fn[len-pos-7];
			memcpy(fn, fa+7, len-pos-7-1);
			fn[len-pos-7-1]=0x00;
			//fn[len-pos-7]=0x00;
			fontName.assign(fn);
		} else
			mHasFontAttribute = false;
        }
}

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

ReceivedSystemIM::ReceivedSystemIM(const unsigned char *buf, const int len)
{
	parseData(buf, len);
}

ReceivedSystemIM::ReceivedSystemIM( const ReceivedSystemIM &rhs)
{
	*this = rhs;
}

ReceivedSystemIM &ReceivedSystemIM::operator=(const ReceivedSystemIM &rhs)
{
	systemIMType = rhs.getSystemIMType();
	message = rhs.getMessage();
        return *this;
}

void ReceivedSystemIM::parseData(const unsigned char *buf, const int len)
{
	int i=0;
	long tmp=0;
	while(!(buf[i++]==0x2f)){
		tmp = (int)(tmp<<8) + (char)buf[i-1];
	}
	systemIMType = tmp;
	  
	char msg[len-i+1];
	memcpy(msg, buf+i, len-i);
	msg[len-i]=0x00;
	message.assign(msg);
}

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

ReceiveIMReplyPacket::ReceiveIMReplyPacket(const char *key) 
	: OutPacket(QQ_CMD_RECV_IM, false)
{
        memcpy(replyKey, key, 16);
}

ReceiveIMReplyPacket::ReceiveIMReplyPacket(const ReceiveIMReplyPacket &rhs)
	: OutPacket(rhs)
{
	memcpy(replyKey, rhs.getReplyKey(), REPLY_KEY_LENGTH);
}

ReceiveIMReplyPacket &ReceiveIMReplyPacket::operator=(const ReceiveIMReplyPacket &rhs)
{
	*((OutPacket *)this) = (OutPacket)rhs;
	memcpy(replyKey, rhs.getReplyKey(), REPLY_KEY_LENGTH);
        return *this;
}

int ReceiveIMReplyPacket::putBody(unsigned char *buf) {

        memcpy(buf, replyKey, REPLY_KEY_LENGTH);
	return REPLY_KEY_LENGTH;
}

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

ReceivedQunIM::ReceivedQunIM( const unsigned char * buf, const int len )
{
	parseData(buf, len);	
}

ReceivedQunIM::ReceivedQunIM( const ReceivedQunIM & rhs )
{
	(*this) = rhs;
}

ReceivedQunIM & ReceivedQunIM::operator =( const ReceivedQunIM & rhs )
{
	externalId = rhs.getExtID();
	type = rhs.getType();
	sender = rhs.getSenderQQ();
	unknown1 = rhs.getUnknown1();
	sequence = rhs.getSequence();
	sentTime = rhs.getSentTime();
	unknown2 = rhs.getUnknown2();
	unknown3 = rhs.getUnknown3();
	message = rhs.getMessage();
	
	mHasFontAttribute = rhs.hasFontAttribute();
	encoding = rhs.getEncoding();
	red = rhs.getRed();
	green = rhs.getGreen();
	blue = rhs.getBlue();
	fontSize = rhs.getFontSize();
	fontName = rhs.getFontName();
	bold = rhs.isBold();
	italic = rhs.isItalic();
	underline = rhs.isUnderline();
	return *this;
}

void ReceivedQunIM::parseData( const unsigned char * buf, const int len )
{
	int pos=0;
	
	int tmp4;
	memcpy(&tmp4, buf, 4);
	externalId = ntohl(tmp4);
	pos+=4;
	
	type = buf[pos++];
	
	memcpy(&tmp4, buf+pos, 4);
	sender = ntohl(tmp4);
	pos+=4;
	
	short tmp2;
	memcpy(&unknown1, buf+pos, 2);
	pos+=2;

	memcpy(&tmp2, buf+pos, 2);
	sequence = ntohs(tmp2);
	pos+=2;
	
	memcpy(&tmp4, buf+pos, 4);
	sentTime = ntohl(tmp4);
	pos+=4;
	
	memcpy(&unknown2, buf+pos, 2);
        pos+=2;

	memcpy(&unknown3, buf+pos, 2);
        pos+=2;

        pos+=2; // ignore 2 bytes;  Luma QQ says it's length for the following data.
			
	int i=0;
	while( (buf[pos++]) != 0x00){
		i++;
	}
	char str[i+1];
	memcpy(str, buf+(pos-i-1), i+1);
	str[i+1]= 0x00;
	message = ReceiveIMPacket::convertToShow(str);
	
	mHasFontAttribute = (len > pos);
        if(mHasFontAttribute) {
		char fa[len-pos];
		memcpy(fa, buf+pos, len-pos);
		fontSize = fa[0] & 0x1F;
		bold = ((fa[0] & 0x20) != 0);
		italic = ((fa[0] & 0x40) != 0);
		underline = ((fa[0] & 0x80) != 0);
		red = fa[1] & 0xFF;
		green = fa[2] & 0xFF;
		blue = fa[3] & 0xFF;
		short tmp2;
		memcpy(&tmp2, fa+5, 2);
		encoding = ntohs(tmp2);
		char fn[len-pos-7];
		memcpy(fn, fa+7, len-pos-7-1);
		fn[len-pos-7-1]=0x00;
		//fn[len-pos-7]=0x00;
		fontName.assign(fn);
        } 
}
