/*
    Copyright (c) 2005 by Olivier Goffart        <ogoffart@ kde.org>

    *************************************************************************
    *                                                                       *
    * 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 "webcam.h"

#if MSN_WEBCAM

#include <stdlib.h>
#include <kdebug.h>
#include <tqregexp.h>
#include <kbufferedsocket.h>
#include <tdelocale.h>
#include <kserversocket.h>
#include <tdemessagebox.h>
#include <tqlabel.h>
#include <tqguardedptr.h>
#include <tqtimer.h>
#include <tqevent.h>
#include <tqdatetime.h>
#include <tdeconfig.h>

#include "dispatcher.h"

#include "mimicwrapper.h"
#include "msnwebcamdialog.h"


#include "avdevice/videodevicepool.h"

using namespace KNetwork;

namespace P2P {

Webcam::Webcam(Who who, const TQString& to, Dispatcher *parent, TQ_UINT32 sessionId)
	: TransferContext(to,parent,sessionId)  , m_who(who) , m_timerId(0)
{
	setType(P2P::WebcamType);
	m_direction = Incoming;
	m_listener  = 0l;
	m_webcamSocket=0L;
//	m_webcamState=wsNegotiating;
	
	m_mimic=0L;
	m_widget=0L;

	TDEConfig *config = TDEGlobal::config();
	config->setGroup( "MSN" );

	// Read the configuration to get the number of frame per second to send
	int webCamFps=config->readNumEntry("WebcamFPS", 25);
	m_timerFps = 1000 / webCamFps;
}

Webcam::~Webcam()
{
	kdDebug(14140) << k_funcinfo<< "################################################" << endl;
	m_dispatcher=0l;
	delete m_mimic;
	delete m_webcamSocket;
	delete m_widget;
	
	if(m_timerId != 0) //if we were sending
	{
		Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self(); 
		videoDevice->stopCapturing(); 
		videoDevice->close();
	}

}

void Webcam::askIncommingInvitation()
{
	m_direction = Incoming;
	//protect, in case this is deleted when the messagebox is active
	TQGuardedPtr<Webcam> _this = this;
	TQString message= (m_who==wProducer)  ?
			i18n("<qt>The contact %1 wants to see <b>your</b> webcam, do you want them to see it?</qt>")  :
			i18n("The contact %1 wants to show you his/her webcam, do you want to see it?")  ;
	int result=KMessageBox::questionYesNo( 0L , message.arg(m_recipient),
										   i18n("Webcam invitation - Kopete MSN Plugin") , i18n("Accept") , i18n("Decline"));
	if(!_this)
		return;
	
	TQString content = TQString("SessionID: %1\r\n\r\n").arg(m_sessionId);
	if(result==KMessageBox::Yes)
	{
		//Send two message, an OK, and an invite.
		//Normaly, the user should decline the invite (i hope)
		
		// Send a 200 OK message to the recipient.
		sendMessage(OK, content);
				
		
		//send an INVITE message we want the user decline
		//need to change the branch of the second message
		m_branch=Uid::createUid();
		m_state = Negotiation;  //set type to application/x-msnmsgr-transreqbody
				
		content=TQString("Bridges: TRUDPv1 TCPv1\r\n"
						"NetID: -1280904111\r\n"
						"Conn-Type: Firewall\r\n"
						"UPnPNat: false\r\n"
						"ICF: false\r\n\r\n");

		sendMessage(INVITE, content);
		
	}
	else
	{
		//Decline the invitation
		sendMessage(DECLINE, content);
		m_state=Finished;
	}
}

void Webcam::sendBYEMessage()
{
	m_state=Finished;
	TQString content="Context: dAMAgQ==\r\n";
	sendMessage(BYE,content);
	
	//If ever the opposite client was dead or something, we'll ack anyway, so everything get cleaned
	TQTimer::singleShot(60*1000 , this, TQT_SLOT(acknowledged()));
}



void Webcam::acknowledged()
{
	kdDebug(14140) << k_funcinfo << endl;
	
	switch(m_state)
	{
		case Invitation:
		{
//			m_state=Negotiation;
			break;
		}
		
		/*
		case Negotiation:
		{
			if(m_type == UserDisplayIcon)
			{
				<<< Data preparation acknowledge message.
				m_state = DataTransfer;
				m_identifier++;
				Start sending data.
				slotSendData();
			}
			break;
		}
		
		case DataTransfer:
			NOTE <<< Data acknowledged message.
			<<< Bye message should follow.
			if(m_type == File)
			{
				if(m_handshake == 0x01)
				{
					Data handshake acknowledge message.
					Start sending data.
					slotSendData();
				}
				else if(m_handshake == 0x02)
				{
					Data acknowledge message.
					Send the recipient a BYE message.
					m_state = Finished;
					sendMessage(BYE, "\r\n");
				}
			}
			
			break;
		*/
		case Finished:
			//BYE or DECLINE acknowledge message.
			m_dispatcher->detach(this);
			break;
		default:
			break;
	}
}




void Webcam::processMessage(const Message& message)
{
	if(message.header.dataOffset+message.header.dataSize >= message.header.totalDataSize)
		acknowledge( message ); //aknowledge if needed
	
	if(message.applicationIdentifier != 4l)
	{
		TQString body = TQCString(message.body.data(), message.header.dataSize);
		kdDebug(14141) << k_funcinfo << "received, " << body << endl;

		if(body.startsWith("MSNSLP/1.0 200 OK"))
		{
			m_direction = Outgoing;
		}
		if(body.startsWith("INVITE"))
		{
			if(m_direction == Outgoing)
			{
				TQRegExp regex(";branch=\\{([0-9A-F\\-]*)\\}\r\n");
				regex.search(body);
				m_branch=regex.cap(1);
				//decline
				sendMessage(DECLINE);
				makeSIPMessage("syn",0x17,0x2a,0x01);
			}
		}
		else if(body.startsWith("MSNSLP/1.0 603 DECLINE"))
		{
			//if it is the declinaison of the second invite message, we have to don't care
			//TODO anyway, if it's the declinaison of our invitation, we have to something
		}
		else if(body.startsWith("BYE"))
		{
			m_state = Finished;

			// Dispose of this transfer context.
			m_dispatcher->detach(this);
		}
		return;
	}
	
	
	
	//Let's take the fun, we entering into the delicious webcam  negotiation binary protocol

	//well, there is maybe better to take utf16,  but it's ascii, so no problem.
	TQByteArray dataMessage=message.body;
	
#if 0
	TQString echoS="";
	unsigned int f=0;
	while(f<dataMessage.size())
	{
		echoS+="\n";
		for(unsigned int q=0; q<16 ; q++)
		{
			if(q+f<dataMessage.size())
			{
				unsigned int N=(unsigned int) (dataMessage[q+f]);
				if(N<16)
					echoS+="0";
				echoS+=TQString::number( N  ,16)+" ";
			}
			else
				echoS+="   ";
		}
		echoS+="   ";
				
		for(unsigned int q=0; (q<16 && (q+f)<dataMessage.size()) ; q++)
		{
			unsigned char X=dataMessage[q+f];
			char C=((char)(( X<128 && X>31 ) ? X : '.'));
			echoS+=TQString::fromLatin1(&C,1);
		}
		f+=16;
	}
	kdDebug(14141) << k_funcinfo << dataMessage.size() << echoS << endl;
#endif
	
	
	
	
	
	for(uint pos=m_content.isNull() ? 10 : 0; pos<dataMessage.size(); pos+=2)
	{
		if(dataMessage[pos] !=0 )
			m_content+=dataMessage[pos];
	}

	if(message.header.dataOffset+message.header.dataSize < message.header.totalDataSize)
		return;

	kdDebug(14141) << k_funcinfo << "Message contents: " << m_content << "\n" << endl;
	if(m_content.startsWith("syn"))
	{
		if(m_direction == Incoming)
			makeSIPMessage("syn",0x17,0x2a,0x01);
		else
			makeSIPMessage("ack",0xea,0x00,0x00);
	}
	else if(m_content.startsWith("ack"))
	{
		if(m_direction == Incoming)
			makeSIPMessage("ack",0xea,0x00,0x00);
		
		if(m_who==wProducer)
		{
			uint sess=rand()%1000+5000;
			uint rid=rand()%100+50;
			m_myAuth=TQString("recipientid=%1&sessionid=%2\r\n\r\n").arg(rid).arg(sess);
			kdDebug(14140) << k_funcinfo << "m_myAuth= " << m_myAuth << endl;
			TQString  producerxml=xml(sess , rid);
			kdDebug(14140) << k_funcinfo << "producerxml= " << producerxml << endl; 
			makeSIPMessage(producerxml);
		}
	}
	else if(m_content.contains("<producer>")   ||  m_content.contains("<viewer>"))
	{
		TQRegExp rx("<rid>([0-9]*)</rid>.*<session>([0-9]*)</session>");
		rx.search(m_content);	
		TQString rid=rx.cap(1);
		TQString sess=rx.cap(2);
		if(m_content.contains("<producer>"))
		{
			
			TQString viewerxml=xml(sess.toUInt() , rid.toUInt());
			kdDebug(14140) << k_funcinfo << "vewerxml= " << viewerxml << endl; 
			makeSIPMessage(  viewerxml ,0x00,0x09,0x00 );
			m_peerAuth=m_myAuth=TQString("recipientid=%1&sessionid=%2\r\n\r\n").arg(rid,sess);
			kdDebug(14140) << k_funcinfo << "m_auth= " << m_myAuth << endl;
		}
		else
		{
			m_peerAuth=TQString("recipientid=%1&sessionid=%2\r\n\r\n").arg(rid,sess);
			
			makeSIPMessage("receivedViewerData", 0xec , 0xda , 0x03);
		}

		if(!m_listener)
		{
			//it should have been creed in xml
			sendBYEMessage();
			return;
		}
		//m_listener->setResolutionEnabled(true);
				// Create the callback that will try to accept incoming connections.
		TQObject::connect(m_listener, TQT_SIGNAL(readyAccept()), this, TQT_SLOT(slotAccept()));
		TQObject::connect(m_listener, TQT_SIGNAL(gotError(int)), this, TQT_SLOT(slotListenError(int)));
				// Listen for incoming connections.
		bool isListening = m_listener->listen();
		kdDebug(14140) << k_funcinfo << (isListening ? TQString("listening %1").arg(m_listener->localAddress().toString()) : TQString("not listening")) << endl;		
		
		rx=TQRegExp("<tcpport>([^<]*)</tcpport>");
		rx.search(m_content);
		TQString port1=rx.cap(1);
		if(port1=="0")
			port1=TQString();
		
		rx=TQRegExp("<tcplocalport>([^<]*)</tcplocalport>");
		rx.search(m_content);
		TQString port2=rx.cap(1);
		if(port2==port1 || port2=="0")
			port2=TQString();
		
		rx=TQRegExp("<tcpexternalport>([^<]*)</tcpexternalport>");
		rx.search(m_content);
		TQString port3=rx.cap(1);
		if(port3==port1 || port3==port2 || port3=="0")
			port3=TQString();

		int an=0;
		while(true)
		{
			an++;
			if(!m_content.contains( TQString("<tcpipaddress%1>").arg(an)  ))
				break;
			rx=TQRegExp(TQString("<tcpipaddress%1>([^<]*)</tcpipaddress%2>").arg(an).arg(an));
			rx.search(m_content);
			TQString ip=rx.cap(1);
			if(ip.isNull())
				continue;
			
			if(!port1.isNull())
			{
				kdDebug(14140) << k_funcinfo << "trying to connect on " << ip <<":" << port1 << endl;
				TDEBufferedSocket *sock=new TDEBufferedSocket( ip, port1, this );
				m_allSockets.append(sock);
				TQObject::connect( sock, TQT_SIGNAL( connected( const KResolverEntry&) ), this, TQT_SLOT( slotSocketConnected() ) );
				TQObject::connect( sock, TQT_SIGNAL( gotError(int)), this, TQT_SLOT(slotSocketError(int)));
				sock->connect(ip, port1);
				kdDebug(14140) << k_funcinfo << "okok " << sock << " - " << sock->peerAddress().toString() << " ; " << sock->localAddress().toString()  << endl;
			}
			if(!port2.isNull())
			{
				kdDebug(14140) << k_funcinfo << "trying to connect on " << ip <<":" << port2 << endl;
				TDEBufferedSocket *sock=new TDEBufferedSocket( ip, port2, this );
				m_allSockets.append(sock);
				TQObject::connect( sock, TQT_SIGNAL( connected( const KResolverEntry&) ), this, TQT_SLOT( slotSocketConnected() ) );
				TQObject::connect( sock, TQT_SIGNAL( gotError(int)), this, TQT_SLOT(slotSocketError(int)));
				sock->connect(ip, port2);
			}
			if(!port3.isNull())
			{
				kdDebug(14140) << k_funcinfo << "trying to connect on " << ip <<":" << port3 << endl;
				TDEBufferedSocket *sock=new TDEBufferedSocket( ip, port3, this );
				m_allSockets.append(sock);
				TQObject::connect( sock, TQT_SIGNAL( connected( const KResolverEntry&) ), this, TQT_SLOT( slotSocketConnected() ) );
				TQObject::connect( sock, TQT_SIGNAL( gotError(int)), this, TQT_SLOT(slotSocketError(int)));
				sock->connect(ip, port3);
			}
		}
		TQValueList<TDEBufferedSocket*>::iterator it;
		for ( it = m_allSockets.begin(); it != m_allSockets.end(); ++it )
		{
			TDEBufferedSocket *sock=(*it);
			
			//sock->enableRead( false );
			kdDebug(14140) << k_funcinfo << "connect to "  << sock << " - "<< sock->peerAddress().toString() << " ; " << sock->localAddress().toString()  << endl;
		}
	}
	else if(m_content.contains("receivedViewerData"))
	{
		//I'm happy you received the xml i sent, really.
	}
	else
		error();
	m_content=TQString();
}

void Webcam::makeSIPMessage(const TQString &message, TQ_UINT8 XX, TQ_UINT8 YY , TQ_UINT8 ZZ)
{
	TQByteArray dataMessage; //(12+message.length()*2);
	TQDataStream writer(dataMessage, IO_WriteOnly);
	writer.setByteOrder(TQDataStream::LittleEndian);
	writer << (TQ_UINT8)0x80;
	writer << (TQ_UINT8)XX;
	writer << (TQ_UINT8)YY;
	writer << (TQ_UINT8)ZZ;
	writer << (TQ_UINT8)0x08;
	writer << (TQ_UINT8)0x00;
	writer << message+'\0';
	//writer << (TQ_UINT16)0x0000;

	/*TQString echoS="";
	unsigned int f=0;
	while(f<dataMessage.size())
	{
		echoS+="\n";
		for(unsigned int q=0; q<16 ; q++)
		{
			if(q+f<dataMessage.size())
			{
				unsigned int N=(unsigned int) (dataMessage[q+f]);
				if(N<16)
					echoS+="0";
				echoS+=TQString::number( N  ,16)+" ";
			}
			else
				echoS+="   ";
		}
		echoS+="   ";
				
		for(unsigned int q=0; (q<16 && (q+f)<dataMessage.size()) ; q++)
		{
			unsigned char X=dataMessage[q+f];
			char C=((char)(( X<128 && X>31 ) ? X : '.'));
			echoS+=TQString::fromLatin1(&C,1);
		}
		f+=16;
	}
	kdDebug(14141) << k_funcinfo << dataMessage.size() << echoS << endl;*/
				
	
	sendBigP2PMessage(dataMessage);
}

void Webcam::sendBigP2PMessage( const TQByteArray & dataMessage)
{
	unsigned int size=m_totalDataSize=dataMessage.size();
	m_offset=0;
	++m_identifier;

	for(unsigned int f=0;f<size;f+=1200)
	{
		m_offset=f;
		TQByteArray dm2;
		dm2.duplicate(dataMessage.data()+m_offset, TQMIN(1200,m_totalDataSize-m_offset));
		sendData( dm2 );
		m_offset+=dm2.size();
	}
	m_offset=0;
	m_totalDataSize=0;
}



TQString Webcam::xml(uint session , uint rid)
{
	TQString who= ( m_who == wProducer ) ? TQString("producer") : TQString("viewer");
	
	TQString ip;
	
	uint ip_number=1;
	TQStringList::iterator it;
	TQStringList ips=m_dispatcher->localIp();
	for ( it = ips.begin(); it != ips.end(); ++it )
	{
		ip+=TQString("<tcpipaddress%1>%2</tcpipaddress%3>").arg(ip_number).arg(*it).arg(ip_number);
		++ip_number;
	}

        TQString port = TQString::number(getAvailablePort());
	
	m_listener = new TDEServerSocket(port, this) ;
	
	return "<" + who + "><version>2.0</version><rid>"+TQString::number(rid)+"</rid><udprid>"+TQString::number(rid+1)+"</udprid><session>"+TQString::number(session)+"</session><ctypes>0</ctypes><cpu>2931</cpu>" +
			"<tcp><tcpport>"+port+"</tcpport>\t\t\t\t\t\t\t\t  <tcplocalport>"+port+"</tcplocalport>\t\t\t\t\t\t\t\t  <tcpexternalport>"+port+"</tcpexternalport>"+ip+"</tcp>"+
			"<udp><udplocalport>7786</udplocalport><udpexternalport>31863</udpexternalport><udpexternalip>"+ ip +"</udpexternalip><a1_port>31859</a1_port><b1_port>31860</b1_port><b2_port>31861</b2_port><b3_port>31862</b3_port><symmetricallocation>1</symmetricallocation><symmetricallocationincrement>1</symmetricallocationincrement><udpversion>1</udpversion><udpinternalipaddress1>127.0.0.1</udpinternalipaddress1></udp>"+
			"<codec></codec><channelmode>1</channelmode></"+who+">\r\n\r\n";
}

int Webcam::getAvailablePort()
{
    TDEConfig *config = TDEGlobal::config();
    config->setGroup( "MSN" );
    TQString basePort=config->readEntry("WebcamPort");
    if(basePort.isEmpty() || basePort == "0" )
		basePort="6891";
	
    uint firstport = basePort.toInt();
    uint maxOffset=config->readUnsignedNumEntry("WebcamMaxPortOffset", 10);
    uint lastport = firstport + maxOffset;

	// try to find an available port
	//
    TDEServerSocket *ss = new TDEServerSocket();
    ss->setFamily(KResolver::InetFamily);
    bool found = false;
	unsigned int port = firstport;
    for( ; port <= lastport; ++port) {
		ss->setAddress( TQString::number( port ) );
		bool success = ss->listen();
		if( found = ( success && ss->error() == TDESocketBase::NoError ) )
			break;
		ss->close();
    }
	delete ss;
	

    kdDebug(14140) << k_funcinfo<< "found available port : " << port << endl;

	return port;
}


/* ---------- Now functions about the dirrect connection  --------- */

void Webcam::slotSocketConnected()
{
	kdDebug(14140) << k_funcinfo <<"##########################" << endl;
	
	m_webcamSocket=const_cast<TDEBufferedSocket*>(static_cast<const TDEBufferedSocket*>(sender()));
	if(!m_webcamSocket)
		return;
	
	kdDebug(14140) << k_funcinfo << "Connection established on  " <<  m_webcamSocket->peerAddress().toString() << " ; " << m_webcamSocket->localAddress().toString()  << endl;
	
	m_webcamSocket->setBlocking(false);
	m_webcamSocket->enableRead(true);
	m_webcamSocket->enableWrite(false);

	// Create the callback that will try to read bytes from the accepted socket.
	TQObject::connect(m_webcamSocket, TQT_SIGNAL(readyRead()),   this, TQT_SLOT(slotSocketRead()));
	// Create the callback that will try to handle the socket close event.
	TQObject::connect(m_webcamSocket, TQT_SIGNAL(closed()),      this, TQT_SLOT(slotSocketClosed()));
	// Create the callback that will try to handle the socket error event.
//	TQObject::connect(m_webcamSocket, TQT_SIGNAL(gotError(int)), this, TQT_SLOT(slotSocketError(int)));

	m_webcamStates[m_webcamSocket]=wsConnected;
	TQCString to_send=m_peerAuth.utf8();
	m_webcamSocket->writeBlock(to_send.data(), to_send.length());
	kdDebug(14140) << k_funcinfo << "sending "<< m_peerAuth << endl;

}


void Webcam::slotAccept()
{
	// Try to accept an incoming connection from the sending client.
	m_webcamSocket = static_cast<TDEBufferedSocket*>(m_listener->accept());
	if(!m_webcamSocket)
	{
		// NOTE If direct connection fails, the sending
		// client wil transfer the file data through the
		// existing session.
		kdDebug(14140) << k_funcinfo << "Direct connection failed." << endl;
		// Close the listening endpoint.
//		m_listener->close();
		return;
	}

	kdDebug(14140) << k_funcinfo << "################################  Direct connection established." << endl;

	// Set the socket to non blocking,
	// enable the ready read signal and disable
	// ready write signal.
	// NOTE readyWrite consumes too much cpu usage.
	m_webcamSocket->setBlocking(false);
	m_webcamSocket->enableRead(true);
	m_webcamSocket->enableWrite(false);

	// Create the callback that will try to read bytes from the accepted socket.
	TQObject::connect(m_webcamSocket, TQT_SIGNAL(readyRead()),   this, TQT_SLOT(slotSocketRead()));
	// Create the callback that will try to handle the socket close event.
	TQObject::connect(m_webcamSocket, TQT_SIGNAL(closed()),      this, TQT_SLOT(slotSocketClosed()));
	// Create the callback that will try to handle the socket error event.
	TQObject::connect(m_webcamSocket, TQT_SIGNAL(gotError(int)), this, TQT_SLOT(slotSocketError(int)));
	
	m_allSockets.append(m_webcamSocket);
	m_webcamStates[m_webcamSocket]=wsNegotiating;
}

void Webcam::slotSocketRead()
{
	m_webcamSocket=const_cast<TDEBufferedSocket*>(static_cast<const TDEBufferedSocket*>(sender()));

	uint available = m_webcamSocket->bytesAvailable();
	kdDebug(14140) << k_funcinfo  <<  m_webcamSocket <<  "############# " << available << " bytes available." << endl;
		
	TQByteArray avail_buff(available);
	m_webcamSocket->peekBlock(avail_buff.data(), avail_buff.size());
	
	kdDebug(14140) << k_funcinfo  <<  m_webcamSocket << avail_buff << endl;
	
	
	
	const TQString connected_str("connected\r\n\r\n");
	switch(m_webcamStates[m_webcamSocket])
	{
		case wsNegotiating:
		{
			if(available < m_myAuth.length())
			{
				kdDebug(14140) << k_funcinfo << "waiting more data   ( " << available << "  of  " <<m_myAuth.length()<< " )"<<  endl;
				break;
			}
			TQByteArray buffer(available);
			m_webcamSocket->readBlock(buffer.data(), buffer.size());
		
			kdDebug(14140) << k_funcinfo << buffer.data() <<  endl;

			if(TQString(buffer) == m_myAuth )
			{
				closeAllOtherSockets();
				kdDebug(14140) << k_funcinfo << "Sending " << connected_str << endl;
				TQCString conne=connected_str.utf8();
				m_webcamSocket->writeBlock(conne.data(), conne.length());
				m_webcamStates[m_webcamSocket]=wsConnecting;
				
				//SHOULD NOT BE THERE
				m_mimic=new MimicWrapper();
				if(m_who==wProducer)
				{
					Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
					videoDevice->open();
					videoDevice->setSize(320, 240);
					videoDevice->startCapturing();
					
					m_timerId=startTimer(m_timerFps);
					kdDebug(14140) << k_funcinfo <<  "new timer" << m_timerId << endl;
				}
				m_widget=new MSNWebcamDialog(m_recipient);
				connect(m_widget, TQT_SIGNAL( closingWebcamDialog() ) , this , TQT_SLOT(sendBYEMessage()));

			}
			else
			{
				kdWarning(14140) << k_funcinfo << "Auth failed" << endl;
				m_webcamSocket->disconnect();
				m_webcamSocket->deleteLater();
				m_allSockets.remove(m_webcamSocket);
				m_webcamSocket=0l;
				//sendBYEMessage();
			}
			break;
		}
		case wsConnecting:
		case wsConnected:
		{
			if(available < connected_str.length())
			{
				kdDebug(14140) << k_funcinfo << "waiting more data   ( " << available << "  of  " <<connected_str.length()<< " )"<<  endl;
				break;
			}
			TQByteArray buffer(connected_str.length());
			m_webcamSocket->readBlock(buffer.data(), buffer.size());
			
// 			kdDebug(14140) << k_funcinfo << "state " << m_webcamState << " received :" << TQCString(buffer) <<  endl;
				
	
			if(TQString(buffer) == connected_str)
			{
				if(m_webcamStates[m_webcamSocket]==wsConnected)
				{
					closeAllOtherSockets();
					kdDebug(14140) << k_funcinfo << "Sending " << connected_str << endl;
					TQCString conne=connected_str.utf8();
					m_webcamSocket->writeBlock(conne.data(), conne.length());
												
					//SHOULD BE DONE IN ALL CASE
				m_mimic=new MimicWrapper();
				if(m_who==wProducer)
				{
					Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
					videoDevice->open();
					videoDevice->setSize(320, 240);
					videoDevice->startCapturing();
					
					m_timerId=startTimer(m_timerFps);
					kdDebug(14140) << k_funcinfo <<  "new timer" << m_timerId << endl;
				}
				m_widget=new MSNWebcamDialog(m_recipient);
				connect(m_widget, TQT_SIGNAL( closingWebcamDialog() ) , this , TQT_SLOT(sendBYEMessage()));
				
				}
				m_webcamStates[m_webcamSocket]=wsTransfer;

			}
			else
			{
				kdWarning(14140) << k_funcinfo << "Connecting failed" << endl;
				m_webcamSocket->disconnect();
				m_webcamSocket->deleteLater();
				m_allSockets.remove(m_webcamSocket);
				m_webcamSocket=0l;
			}
			break;
		}
		case wsTransfer:
		{
			if(m_who==wProducer)
			{
				kdWarning(14140) << k_funcinfo << "data received when we are producer"<<  endl;
				break;
			}
			if(available < 24)
			{
				kdDebug(14140) << k_funcinfo << "waiting more data   ( " << available << "  of  " <<24<< " )"<<  endl;
				break;
			}
			TQByteArray buffer(24);
			m_webcamSocket->peekBlock(buffer.data(), buffer.size());
			
			TQ_UINT32 paysize=(uchar)buffer[8] + ((uchar)buffer[9]<<8) + ((uchar)buffer[10]<<16) + ((uchar)buffer[11]<<24);
			
			if(available < (paysize+24))
			{
				kdDebug(14140) << k_funcinfo << "waiting more data   ( " << available << "  of  " <<paysize<< " )"<<  endl;
				break;
			}
			m_webcamSocket->readBlock(buffer.data(), 24); //flush
			buffer.resize(paysize);
			m_webcamSocket->readBlock(buffer.data(), buffer.size());
			
			TQPixmap pix=m_mimic->decode(buffer);
			if(pix.isNull())
			{
				kdWarning(14140) << k_funcinfo << "incorrect pixmap returned, better to stop everything"<<  endl;
				m_webcamSocket->disconnect();
				sendBYEMessage();
			}
			m_widget->newImage(pix);
			break;
		}
		default:
			break;
	}

}

void Webcam::slotListenError(int errorCode)
{
	kdWarning(14140) << k_funcinfo << "Error " << errorCode << " : " << m_listener->errorString() << endl;
}

void Webcam::slotSocketClosed()
{
	if(!m_dispatcher) //we are in this destructor
		return; 
	
	TDEBufferedSocket *m_webcamSocket=const_cast<TDEBufferedSocket*>(static_cast<const TDEBufferedSocket*>(sender()));
	
	kdDebug(14140) << k_funcinfo <<  m_webcamSocket <<  endl;
	
	if(m_listener)
	{ //if we are still waiting for other socket to connect, just remove this socket from the socket list
		m_webcamSocket->disconnect();
		m_webcamSocket->deleteLater();
		m_allSockets.remove(m_webcamSocket);
		m_webcamSocket=0l;
	}
	else // else, close the session
		sendBYEMessage();
	
}

void Webcam::slotSocketError(int errorCode)
{
	TDEBufferedSocket *socket=const_cast<TDEBufferedSocket*>(static_cast<const TDEBufferedSocket*>(sender()));
	kdDebug(14140) << k_funcinfo <<  socket << " -  " << errorCode << " : " << socket->TDESocketBase::errorString() << endl;
	//sendBYEMessage();
}

void Webcam::closeAllOtherSockets()
{
	//m_lisener->close();
	delete m_listener;
	m_listener=0l;
	
	TQValueList<TDEBufferedSocket*>::iterator it;
	for ( it = m_allSockets.begin(); it != m_allSockets.end(); ++it )
	{
		TDEBufferedSocket *sock=(*it);
		if(sock != m_webcamSocket)
			delete sock;
	}
	m_allSockets.clear();
}


void Webcam::timerEvent( TQTimerEvent *e )
{
	if(e->timerId() != m_timerId)
		return TransferContext::timerEvent(e);
	
//	kdDebug(14140) << k_funcinfo << endl;
		
	Kopete::AV::VideoDevicePool *videoDevice = Kopete::AV::VideoDevicePool::self();
	videoDevice->getFrame();
	TQImage img;
	videoDevice->getImage(&img);
	
	if(m_widget)
		m_widget->newImage(img);
	
	if(img.width()!=320 || img.height()!=240)
	{
		kdWarning(14140) << k_funcinfo << "Bad image size " <<img.width() << "x" <<  img.height() << endl;
		return;
	}

	uchar *bits=img.bits();
	TQByteArray image_data(img.width()*img.height()*3);
	uint b2=0;
	uint imgsize=img.width()*img.height()*4;
	for(uint f=0; f< imgsize; f+=4)
	{
		image_data[b2+0]=bits[f+2];
		image_data[b2+1]=bits[f+1];
		image_data[b2+2]=bits[f+0];
		b2+=3;
	}
	
	TQByteArray frame=m_mimic->encode(image_data);
	
	
	kdDebug(14140) << k_funcinfo << "Sendinf frame of size " << frame.size() << endl;
	//build the header.
	TQByteArray header;
	
	TQDataStream writer(header, IO_WriteOnly);
	writer.setByteOrder(TQDataStream::LittleEndian);
	writer << (TQ_UINT16)24;  // header size
	writer << (TQ_UINT16)img.width();
	writer << (TQ_UINT16)img.height();
	writer << (TQ_UINT16)0x0000; //wtf .?
	writer << (TQ_UINT32)frame.size();
	writer << (TQ_UINT8)('M') << (TQ_UINT8)('L') << (TQ_UINT8)('2') << (TQ_UINT8)('0');
	writer << (TQ_UINT32)0x00000000; //wtf .?
	writer << TQTime::currentTime();  //FIXME:  possible midnight bug ?

	m_webcamSocket->writeBlock(header.data(), header.size());
	m_webcamSocket->writeBlock(frame.data(), frame.size());
}


}


#include "webcam.moc"

#endif