Index: protocols/configure.in.in
===================================================================
--- protocols/configure.in.in	(revision 614319)
+++ protocols/configure.in.in	(working copy)
@@ -204,6 +204,7 @@
 AC_MSG_CHECKING([if MSN webcam support should be enabled])
 AC_MSG_RESULT($compile_msn_webcam)
 AC_DEFINE_UNQUOTED(MSN_WEBCAM, $msn_webcam_val, [Define if MSN webcam support can be enabled])
+AC_DEFINE_UNQUOTED(SUPPORT_MIMIC, $msn_webcam_val, [Define if Jabber webcam support can be enabled])
 
 AM_CONDITIONAL(include_msn_webcam, test "x$compile_msn_webcam" = "xyes")
 
Index: protocols/jabber/jabbercontact.h
===================================================================
--- protocols/jabber/jabbercontact.h	(revision 614319)
+++ protocols/jabber/jabbercontact.h	(working copy)
@@ -113,6 +113,14 @@
 	 * this will start a voice call to the contact
 	 */
 	void voiceCall();
+	/**
+	 * this will start a mimic call to the contact
+	 */
+	void webcamReceive();
+	/**
+	 * this will start a mimic call to the contact
+	 */
+	void webcamSend();
 
 private slots:
 
Index: protocols/jabber/jabberaccount.h
===================================================================
--- protocols/jabber/jabberaccount.h	(revision 614319)
+++ protocols/jabber/jabberaccount.h	(working copy)
@@ -51,7 +51,6 @@
 class VoiceCaller;
 #endif
 
-
 /* @author Daniel Stone, Till Gerken */
 
 class JabberAccount : public Kopete::PasswordedAccount
@@ -96,6 +95,8 @@
 // 	}
 #endif
 
+	
+	
 	// change the default S5B server port
 	void setS5BServerPort ( int port );
 
Index: protocols/jabber/jabberclient.h
===================================================================
--- protocols/jabber/jabberclient.h	(revision 614319)
+++ protocols/jabber/jabberclient.h	(working copy)
@@ -22,6 +22,11 @@
 #ifndef JABBERCLIENT_H
 #define JABBERCLIENT_H
 
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <qobject.h>
 
 // include these because of namespace reasons
@@ -398,6 +403,13 @@
 	 * Request the roster from the Jabber server.
 	 */
 	void requestRoster ();
+	
+#ifdef SUPPORT_MIMIC
+	/**
+	 * 
+	 */
+	void startMimicWebcam( const QString &to ,  bool wantToReceive );
+#endif
 
 signals:
 	/**
Index: protocols/jabber/jabbercontact.cpp
===================================================================
--- protocols/jabber/jabbercontact.cpp	(revision 614319)
+++ protocols/jabber/jabbercontact.cpp	(working copy)
@@ -230,6 +230,7 @@
 	
 	
 #ifdef SUPPORT_JINGLE
+	{
 	KAction *actionVoiceCall = new KAction (i18n ("Voice call"), "voicecall", 0, this, SLOT (voiceCall ()), this, "jabber_voicecall");
 	actionVoiceCall->setEnabled( false );
 
@@ -241,8 +242,30 @@
 	{
 		actionVoiceCall->setEnabled( true );
 	}
+	}
 #endif
+#ifdef SUPPORT_MIMIC
+	{
+	// Invite to receive webcam action
+	KAction *actionWebcamReceive=new KAction( i18n( "View Contact's Webcam" ), "webcamreceive",  0, this, SLOT(webcamReceive()), this, "msnWebcamReceive" ) ;
+	actionWebcamReceive->setEnabled( false );
+		
+	//Send webcam action
+	KAction *actionWebcamSend=new KAction( i18n( "Send Webcam" ), "webcamsend",  0, this, SLOT(webcamSend()), this, "msnWebcamSend" ) ;
+	actionWebcamSend->setEnabled( false );
 	
+	actionCollection->append(actionWebcamReceive);
+	actionCollection->append(actionWebcamSend);
+			
+	// Check if the current contact support Voice calls, also honour lock by default.
+	JabberResource *bestResource = account()->resourcePool()->  bestJabberResource( mRosterItem.jid() );
+	if( bestResource && bestResource->features().list().contains("http://kopete.kde.org/protocol/mimic") )
+	{
+		actionWebcamReceive->setEnabled( true );
+		actionWebcamSend->setEnabled( true );
+	}
+	}
+#endif
 	return actionCollection;
 }
 
@@ -1323,6 +1346,47 @@
 	}
 }
 
+void JabberContact::webcamReceive( )
+{
+#ifdef SUPPORT_MIMIC
+	Jid jid = mRosterItem.jid();
+	
+	// It's honour lock by default.
+	JabberResource *bestResource = account()->resourcePool()->bestJabberResource( jid );
+	if( account()->client() && bestResource )
+	{
+		if( jid.resource().isEmpty() )
+		{
+			// If the jid resource is empty, get the JID from best resource for this contact.
+			jid = bestResource->jid();
+		}
+		if( bestResource && bestResource->features().list().contains("http://kopete.kde.org/protocol/mimic") )
+			account()->client()->startMimicWebcam( jid.full() , true );
+	}
+#endif
+}
 
 
+void JabberContact::webcamSend( )
+{
+#ifdef SUPPORT_MIMIC
+	Jid jid = mRosterItem.jid();
+	
+	// It's honour lock by default.
+	JabberResource *bestResource = account()->resourcePool()->bestJabberResource( jid );
+	if( account()->client() && bestResource )
+	{
+		if( jid.resource().isEmpty() )
+		{
+			// If the jid resource is empty, get the JID from best resource for this contact.
+			jid = bestResource->jid();
+		}
+		if( bestResource && bestResource->features().list().contains("http://kopete.kde.org/protocol/mimic") )
+			account()->client()->startMimicWebcam( jid.full() , false );
+	}
+#endif
+}
+
+
+
 #include "jabbercontact.moc"
Index: protocols/jabber/jabberaccount.cpp
===================================================================
--- protocols/jabber/jabberaccount.cpp	(revision 614319)
+++ protocols/jabber/jabberaccount.cpp	(working copy)
@@ -83,6 +83,7 @@
 #include "jinglevoicesessiondialog.h"
 #endif
 
+
 #define KOPETE_CAPS_NODE "http://kopete.kde.org/jabber/caps"
 
 
@@ -577,6 +578,8 @@
 
 	kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Requesting roster..." << endl;
 	m_jabberClient->requestRoster ();
+	
+
 }
 
 void JabberAccount::slotRosterRequestFinished ( bool success )
Index: protocols/jabber/jabberchatui.rc
===================================================================
--- protocols/jabber/jabberchatui.rc	(revision 614319)
+++ protocols/jabber/jabberchatui.rc	(working copy)
@@ -1,9 +1,11 @@
 <!DOCTYPE kpartgui>
-<kpartgui version="11" name="kopete_jabber_chat">
+<kpartgui version="12" name="kopete_jabber_chat">
 	<MenuBar>
 		<Menu noMerge="1" name="file">
 			<text>&amp;Chat</text>
 			<Action name="jabber_voicecall" />
+			<Action name="msnWebcamReceive" />
+			<Action name="msnWebcamSend" />
 			<Action name="jabberSendFile" />
 		</Menu>
 	</MenuBar>
@@ -12,6 +14,8 @@
 	<ToolBar name="statusToolBar">
 		<Action name="jabberDisplayPicture" />
 		<Action name="jabber_voicecall" />
+		<Action name="msnWebcamReceive" />	
+		<Action name="msnWebcamSend" />
 		<Action name="jabberSendFile" />		
 	</ToolBar>
 
Index: protocols/jabber/webcam/mimictaskpush.cpp
===================================================================
--- protocols/jabber/webcam/mimictaskpush.cpp	(revision 0)
+++ protocols/jabber/webcam/mimictaskpush.cpp	(revision 0)
@@ -0,0 +1,74 @@
+/*
+    Copyright (c) 2006 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 "dispatcher.h"
+#include "mimictaskpush.h"
+#include "xmpp_xmlcommon.h"
+
+#include <kmdcodec.h>
+#include <kdebug.h>
+
+
+MimicTaskPush::MimicTaskPush(XMPP::Task *parent, const QString &from, const QString &ip) 
+	: XMPP::Task(parent)
+{
+	QStringList ips;
+	ips << ip;
+	m_dispatcher=new P2P::Dispatcher(this , from, ips);
+}
+MimicTaskPush::~MimicTaskPush(){}
+
+bool MimicTaskPush::take(const QDomElement &x)
+{
+	if(x.tagName() != "iq" || x.attribute("type") != "set")
+		return false;
+	
+	bool found=true;
+	QDomElement first = findSubTag(x, "msnp2p", &found);
+	
+	if( found && !first.isNull() && first.attribute("xmlns") ==  MIMIC_NS  ) 
+	{
+	 	QString from = x.attribute("from");
+		QString t = first.text();
+		
+		QByteArray stream;
+		KCodecs::base64Decode(t.utf8(),stream);
+		
+		m_last = from;
+		
+		m_dispatcher->slotReadMessage(from,stream);
+
+		QDomElement iq = createIQ(doc(), "result", from, x.attribute("id"));
+		send(iq);
+		
+		return true;
+	}
+	
+	return false;
+}
+
+XMPP::Jid MimicTaskPush::last( )
+{
+	return m_last;
+}
+
+void MimicTaskPush::startWebcam( const QString & myHandle, const QString & msgFullJid, bool wantToReceive )
+{
+	m_last=msgFullJid;
+	m_dispatcher->startWebcam( myHandle, msgFullJid,  wantToReceive );
+}
+
+
+
+#include "mimictaskpush.moc"
Index: protocols/jabber/webcam/dispatcher.cpp
===================================================================
--- protocols/jabber/webcam/dispatcher.cpp	(revision 0)
+++ protocols/jabber/webcam/dispatcher.cpp	(revision 0)
@@ -0,0 +1,486 @@
+/*
+
+	this is an implementation of the MSN P2P base which allow to encapsulate
+	MSN on Jabber 
+
+    Copyright (c) 2006 by Olivier Goffart        <ogoffart @ kde.org>
+    
+    
+    original code from msn
+    
+    Copyright (c) 2003-2005 by Olivier Goffart        <ogoffart@ kde.org>
+    Copyright (c) 2005      by Gregg Edghill          <gregg.edghill@gmail.com>
+
+
+    *************************************************************************
+    *                                                                       *
+    * This program is free software; you can redistribute it and/or modify  *
+    * it under the terms of the GNU General Public License as published by  *
+    * the Free Software Foundation; either version 2 of the License, or     *
+    * (at your option) any later version.                                   *
+    *                                                                       *
+    *************************************************************************
+*/
+
+
+#include "dispatcher.h"
+
+#if MSN_WEBCAM
+#include "webcam.h"
+#endif
+
+using P2P::Dispatcher;
+using P2P::Message;
+using P2P::TransferContext;
+using P2P::IncomingTransfer;
+using P2P::OutgoingTransfer;
+
+// Kde includes
+#include <kdebug.h>
+#include <kmdcodec.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+
+// Qt includes
+#include <qdatastream.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qtextcodec.h>
+#include <qtextstream.h>
+#include <qtimer.h>
+
+// Kopete includes
+#include <kopetechatsession.h>  // Just for getting the contact
+#include <kopeteaccount.h>
+#include <kopetetransfermanager.h>
+
+#include <stdlib.h>
+
+Dispatcher::Dispatcher(QObject *parent, const QString& contact, const QStringList &ip)
+	: QObject(parent) ,  m_contact(contact) , m_callbackChannel(0l) , m_ip(ip)
+{}
+
+Dispatcher::~Dispatcher()
+{
+	kdDebug(14140) << k_funcinfo << endl;
+
+	if(m_callbackChannel)
+	{
+		delete m_callbackChannel;
+		m_callbackChannel = 0l;
+	}
+}
+
+void Dispatcher::detach(TransferContext* transfer)
+{
+	m_sessions.remove(transfer->m_sessionId);
+	transfer->deleteLater();
+}
+
+QString Dispatcher::localContact()
+{
+	return m_contact;
+}
+
+
+//BEGIN J
+/*
+void Dispatcher::requestDisplayIcon(const QString& from, const QString& msnObject)
+{
+}
+
+void Dispatcher::sendFile(const QString& path, Q_INT64 fileSize, const QString& to)
+{
+}
+
+void Dispatcher::sendImage(const QString& fileName, const QString& to)
+{
+}
+*/
+//END J
+
+#if MSN_WEBCAM
+void Dispatcher::startWebcam(const QString &/*myHandle*/, const QString &msgHandle, bool wantToReceive)
+{
+	Q_UINT32 sessionId = rand()%0xFFFFFF00 + 4;
+	Webcam::Who who= wantToReceive ? Webcam::wViewer : Webcam::wProducer;
+	TransferContext* current =
+			new Webcam(who, msgHandle, this, sessionId);
+
+	current->m_branch = P2P::Uid::createUid();
+	current->m_callId = P2P::Uid::createUid();
+	current->setType(P2P::WebcamType);
+	// Add the transfer to the list.
+	m_sessions.insert(sessionId, current);
+
+	//  {4BD96FC0-AB17-4425-A14A-439185962DC8}  <- i want to show you my webcam
+	//  {1C9AA97E-9C05-4583-A3BD-908A196F1E92}  <- i want to see your webcam
+	QString GUID= (who==Webcam::wProducer) ? "4BD96FC0-AB17-4425-A14A-439185962DC8" : "1C9AA97E-9C05-4583-A3BD-908A196F1E92"  ;
+
+	QString content="EUF-GUID: {"+GUID+"}\r\n"
+			"SessionID: "+ QString::number(sessionId)+"\r\n"
+			"AppID: 4\r\n"
+			"Context: ewBCADgAQgBFADcAMABEAEUALQBFADIAQwBBAC0ANAA0ADAAMAAtAEEARQAwADMALQA4ADgARgBGADgANQBCADkARgA0AEUAOAB9AA==\r\n\r\n";
+
+        // context is the base64 of the utf16 of {B8BE70DE-E2CA-4400-AE03-88FF85B9F4E8}
+
+	current->sendMessage( INVITE , content );
+}
+#endif
+
+
+
+void Dispatcher::slotReadMessage(const QString &from, const QByteArray& stream)
+{
+	P2P::Message receivedMessage =
+		m_messageFormatter.readMessage(stream);
+
+	receivedMessage.source = from;
+
+	if(receivedMessage.contentType == "application/x-msnmsgrp2p")
+	{
+		if((receivedMessage.header.dataSize == 0)/* && ((receivedMessage.header.flag & 0x02) == 0x02)*/)
+		{
+			TransferContext *current = 0l;
+			QMap<Q_UINT32, TransferContext*>::Iterator it = m_sessions.begin();
+			for(; it != m_sessions.end(); it++)
+			{
+				if(receivedMessage.header.ackSessionIdentifier == it.data()->m_identifier){
+					current = it.data();
+					break;
+				}
+			}
+
+			if(current){
+    			// Inform the transfer object of the acknowledge.
+    			current->m_ackSessionIdentifier = receivedMessage.header.identifier;
+    			current->m_ackUniqueIdentifier = receivedMessage.header.ackSessionIdentifier;
+				current->acknowledged();
+			}
+			else
+			{
+				kdDebug(14140) << k_funcinfo
+					<< "no transfer context with identifier, "
+					<< receivedMessage.header.ackSessionIdentifier
+					<< endl;
+			}
+			return;
+		}
+
+		if(m_messageBuffer.contains(receivedMessage.header.identifier))
+		{
+			kdDebug(14140) << k_funcinfo
+				<< QString("retrieving buffered messsage, %1").arg(receivedMessage.header.identifier)
+				<< endl;
+
+			// The message was split, try to reconstruct the message
+			// with this received piece.
+			Message bufferedMessage = m_messageBuffer[receivedMessage.header.identifier];
+			// Remove the buffered message.
+			m_messageBuffer.remove(receivedMessage.header.identifier);
+
+			bufferedMessage.body.resize(bufferedMessage.body.size() + receivedMessage.header.dataSize);
+			for(Q_UINT32 i=0; i < receivedMessage.header.dataSize; i++){
+				// Add the remaining message data to the buffered message.
+				bufferedMessage.body[receivedMessage.header.dataOffset + i] = receivedMessage.body[i];
+			}
+			bufferedMessage.header.dataSize += receivedMessage.header.dataSize;
+			bufferedMessage.header.dataOffset = 0;
+
+			receivedMessage = bufferedMessage;
+		}
+
+		// Dispatch the received message.
+		dispatch(receivedMessage);
+	}
+}
+
+void Dispatcher::dispatch(const P2P::Message& message)
+
+{
+	TransferContext *messageHandler = 0l;
+
+	if(message.header.sessionId > 0)
+	{
+		if(m_sessions.contains(message.header.sessionId)){
+			messageHandler = m_sessions[message.header.sessionId];
+		}
+	}
+	else
+	{
+		QString body =
+			QCString(message.body.data(), message.header.dataSize);
+		QRegExp regex("SessionID: ([0-9]*)\r\n");
+		if(regex.search(body) > 0)
+		{
+			Q_UINT32 sessionId = regex.cap(1).toUInt();
+			if(m_sessions.contains(sessionId)){
+				// Retrieve the message handler associated with the specified session Id.
+				messageHandler = m_sessions[sessionId];
+			}
+		}
+		else
+		{
+			// Otherwise, try to retrieve the message handler
+			// based on the acknowlegded unique identifier.
+			if(m_sessions.contains(message.header.ackUniqueIdentifier)){
+				messageHandler =
+					m_sessions[message.header.ackUniqueIdentifier];
+			}
+
+			if(!messageHandler)
+			{
+				// If the message handler still has not been found,
+				// try to retrieve the handler based on the call id.
+				regex = QRegExp("Call-ID: \\{([0-9A-F\\-]*)\\}\r\n");
+				regex.search(body);
+				QString callId = regex.cap(1);
+
+				TransferContext *current = 0l;
+				QMap<Q_UINT32, TransferContext*>::Iterator it = m_sessions.begin();
+				for(; it != m_sessions.end(); it++)
+				{
+					current = it.data();
+					if(current->m_callId == callId){
+						messageHandler = current;
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	if(messageHandler){
+		// Process the received message using the
+		// retrieved registered handler.
+		messageHandler->m_ackSessionIdentifier = message.header.identifier;
+    	messageHandler->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
+		messageHandler->processMessage(message);
+	}
+	else
+	{
+		// There are no objects registered, with the retrieved session Id,
+		// to handle the received message; default to this dispatcher.
+		if(message.header.totalDataSize > message.header.dataOffset + message.header.dataSize)
+		{
+			// The entire message has not been received;
+			// buffer the recevied portion of the original message.
+			kdDebug(14140) << k_funcinfo
+				<< QString("Buffering messsage, %1").arg(message.header.identifier)
+				<< endl;
+			m_messageBuffer.insert(message.header.identifier, message);
+			return;
+		}
+
+		QString body =
+			QCString(message.body.data(), message.header.dataSize);
+		kdDebug(14140) << k_funcinfo << "received, " << body << endl;
+
+		if(body.startsWith("INVITE"))
+		{
+			// Retrieve the branch, call id, and session id.
+			// These fields will be used later on in the p2p
+			// transaction.
+			QRegExp regex(";branch=\\{([0-9A-F\\-]*)\\}\r\n");
+			regex.search(body);
+			QString branch = regex.cap(1);
+			regex = QRegExp("Call-ID: \\{([0-9A-F\\-]*)\\}\r\n");
+			regex.search(body);
+			QString callId = regex.cap(1);
+			regex = QRegExp("SessionID: ([0-9]*)\r\n");
+			regex.search(body);
+			QString sessionId = regex.cap(1);
+			// Retrieve the contact that requested the session.
+			regex = QRegExp("From: <msnmsgr:([^>]*)>");
+			regex.search(body);
+			QString from = regex.cap(1);
+			// Retrieve the application identifier which
+			// is used to determine what type of session
+			// is being requested.
+			regex = QRegExp("AppID: ([0-9]*)\r\n");
+			regex.search(body);
+			Q_UINT32 applicationId = regex.cap(1).toUInt();
+//BEGIN J
+/*			if(applicationId == 1  || applicationId == 12)
+			{                         //the AppID is 12 since Messenger 7.5
+				// A contact has requested a session to download
+				// a display icon (User Display Icon or CustomEmotion).
+				...
+			}
+			else if(applicationId == 2)
+			{
+				// A contact has requested a session to
+				// send a file.
+
+				...
+			}
+			else*/
+//END J
+			
+			if(applicationId == 4)
+			{
+#if MSN_WEBCAM
+				regex = QRegExp("EUF-GUID: \\{([0-9a-zA-Z\\-]*)\\}");
+				regex.search(body);
+				QString GUID=regex.cap(1);
+
+				kdDebug(14140) << k_funcinfo << "webcam " << GUID << endl;
+
+				Webcam::Who who;
+				if(GUID=="4BD96FC0-AB17-4425-A14A-439185962DC8")
+				{  //that mean "I want to send MY webcam"
+					who=Webcam::wViewer;
+				}
+				else if(GUID=="1C9AA97E-9C05-4583-A3BD-908A196F1E92")
+				{ //that mean "I want YOU to send YOUR webcam"
+					who=Webcam::wProducer;
+				}
+				else
+				{ //unknown GUID
+					//current->error();
+					kdWarning(14140) << k_funcinfo << "Unknown GUID " << GUID << endl;
+					return;
+				}
+
+				TransferContext *current = new P2P::Webcam(who, from, this, sessionId.toUInt());
+				current->m_branch = branch;
+				current->m_callId = callId;
+
+					// Add the transfer to the list.
+				m_sessions.insert(sessionId.toUInt(), current);
+					// Acknowledge the session request.
+				current->acknowledge(message);
+				QTimer::singleShot(0,current, SLOT(askIncommingInvitation()) );
+#endif
+			}
+		}
+//BEGIN J
+		/*else if(message.header.sessionId == 64)
+		{
+			// A contact has sent an inkformat (handwriting) gif.
+			...
+		}
+		*/
+//END J
+	}
+}
+
+void Dispatcher::messageAcknowledged(unsigned int correlationId, bool fullReceive)
+{
+	if(fullReceive)
+	{
+		TransferContext *current = 0l;
+		QMap<Q_UINT32, TransferContext*>::Iterator it = m_sessions.begin();
+		for(; it != m_sessions.end(); it++)
+		{
+			current = it.data();
+			if(current->m_transactionId == correlationId)
+			{
+				// Inform the transfer object of the acknowledge.
+				current->readyWrite();
+				break;
+			}
+		}
+	}
+}
+//BEGIN J
+		/*
+Kopete::Contact* Dispatcher::getContactByAccountId(const QString& accountId)
+{
+}
+*/
+
+
+#include "im.h"
+#include "xmpp_xmlcommon.h"
+#include "mimictaskpush.h"
+				 
+class MimicTask : public XMPP::Task
+{
+	public:
+		MimicTask(XMPP::Task *parent) : XMPP::Task(parent) {}
+		~MimicTask(){}
+
+		void set(const QString &  to ,const QByteArray& stream);
+		void onGo();
+		bool take(const QDomElement &);
+		
+	private:
+		QDomElement iq;
+};
+
+
+
+void MimicTask::set(const QString &  to ,const QByteArray& stream)
+{
+	QString t = QString::fromUtf8(KCodecs::base64Encode(stream));
+	QDomNode n=doc()->createTextNode(t);
+	iq = createIQ(doc(), "set" , to , id() );
+	QDomElement query = doc()->createElement("msnp2p");
+	query.setAttribute("xmlns", MIMIC_NS);
+	iq.appendChild(query);
+	query.appendChild(n);
+}
+
+void MimicTask::onGo()
+{
+	send(iq);
+}
+
+bool MimicTask::take(const QDomElement &x)
+{
+	QString to = client()->host();
+	if(!iqVerify(x, to, id()))
+		return false;
+
+	if(x.attribute("type") == "result") {
+		setSuccess();
+	} else {
+		setError(x);
+	}
+	return true;
+}
+
+
+struct MSNSwitchBoardSocket
+{
+	XMPP::Client *client;
+	QString to;
+};
+
+
+Dispatcher::CallbackChannel::CallbackChannel(MSNSwitchBoardSocket *switchboard)
+{
+	m_switchboard = switchboard;
+}
+
+Dispatcher::CallbackChannel::~CallbackChannel()
+{
+	delete m_switchboard;
+}
+
+Q_UINT32 Dispatcher::CallbackChannel::send(const QByteArray& stream)
+{
+	MimicTask *task = new MimicTask( m_switchboard->client->rootTask () );
+	task->set(m_switchboard->to, stream);
+	task->go ( true );	
+	return 1;
+}
+
+Dispatcher::CallbackChannel* Dispatcher::callbackChannel()
+{
+	delete m_callbackChannel;
+	
+	MimicTaskPush *push = dynamic_cast<MimicTaskPush*>(parent());
+		
+	MSNSwitchBoardSocket *callback = new MSNSwitchBoardSocket;
+	callback->client = push->client();
+	callback->to = push->last().full();
+	m_callbackChannel = new Dispatcher::CallbackChannel(callback);
+	
+	return m_callbackChannel;
+}
+
+//END J
+
+#include "dispatcher.moc"
Index: protocols/jabber/webcam/mimictaskpush.h
===================================================================
--- protocols/jabber/webcam/mimictaskpush.h	(revision 0)
+++ protocols/jabber/webcam/mimictaskpush.h	(revision 0)
@@ -0,0 +1,48 @@
+/*
+    Copyright (c) 2006 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.                                   *
+    *                                                                       *
+    *************************************************************************
+*/
+
+
+#ifndef MIMICTASKPUSH
+#define MIMICTASKPUSH
+
+#include <im.h>
+
+#define MIMIC_NS  "http://kopete.kde.org/protocol/mimic"
+
+namespace P2P
+{
+	class Dispatcher;
+}
+
+class MimicTaskPush : public XMPP::Task
+{
+	Q_OBJECT
+	public:
+		MimicTaskPush(XMPP::Task *parent, const QString &from,const QString &ip);
+		~MimicTaskPush();
+
+		bool take(const QDomElement &);
+		
+		void startWebcam(const QString &myHandle, const QString &msgFullJid, bool wantToReceive);
+		
+		XMPP::Jid last();
+		
+	private:
+		P2P::Dispatcher *m_dispatcher;
+		XMPP::Jid m_last;
+
+};
+
+#endif
+
Index: protocols/jabber/webcam/Makefile.am
===================================================================
--- protocols/jabber/webcam/Makefile.am	(revision 0)
+++ protocols/jabber/webcam/Makefile.am	(revision 0)
@@ -0,0 +1,19 @@
+METASOURCES = AUTO
+AM_CPPFLAGS = $(KOPETE_INCLUDES) \
+	-I$(srcdir)/../libiris/iris/include \
+	-I$(srcdir)/../libiris/iris/xmpp-im \
+	-I$(srcdir)/../libiris/iris/jabber \
+	-I$(srcdir)/../libiris/qca/src \
+	-I$(srcdir)/../libiris/cutestuff/util \
+	-I$(srcdir)/../../msn \
+	-I$(srcdir)/../../msn/webcam \
+	-I$(srcdir)/.. \
+	$(all_includes)
+
+noinst_LTLIBRARIES = libkopetejabberwebcam.la 
+
+
+libkopetejabberwebcam_la_SOURCES =  dispatcher.cpp mimictaskpush.cpp ../../msn/webcam.cpp ../../msn/p2p.cpp ../../msn/messageformatter.cpp
+
+libkopetejabberwebcam_la_LIBADD = ../../msn/webcam/libmimicwrapper.la ../../../libkopete/avdevice/libkopete_videodevice.la 
+	$(EXPAT_LIBS) $(ORTP_LIBS) -lpthread $(ILBC_LIBS) $(SPEEX_LIBS) $(GLIB_LIBS) $(ALSA_LIBS)
Index: protocols/jabber/jabberclient.cpp
===================================================================
--- protocols/jabber/jabberclient.cpp	(revision 614319)
+++ protocols/jabber/jabberclient.cpp	(working copy)
@@ -19,6 +19,12 @@
  *                                                                         *
  ***************************************************************************/
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+
 #include "jabberclient.h"
 
 #include <qtimer.h>
@@ -32,12 +38,20 @@
 #include "jabberconnector.h"
 
 #define JABBER_PENALTY_TIME	2
+#ifdef SUPPORT_MIMIC
+#include "webcam/mimictaskpush.h"
+#endif
 
+
 class JabberClient::Private
 {
 public:
 	Private()
 	 : jabberClient(0L), jabberClientStream(0L), jabberClientConnector(0L), jabberTLS(0L), jabberTLSHandler(0L)
+#ifdef SUPPORT_MIMIC
+	,mimic(0L)
+#endif
+
 	{}
 	~Private()
 	{
@@ -113,6 +127,11 @@
 	// Caps(JEP-0115: Entity Capabilities) information
 	QString capsNode, capsVersion;
 	DiscoItem::Identity discoIdentity;
+	
+#ifdef SUPPORT_MIMIC
+	MimicTaskPush *mimic;
+#endif
+
 };
 
 XMPP::S5BServer *JabberClient::Private::s5bServer = 0L;
@@ -986,6 +1005,12 @@
 
 	// start the client operation
 	d->jabberClient->start ( jid().domain (), jid().node (), d->password, jid().resource () );
+	
+#ifdef SUPPORT_MIMIC
+	d->mimic = new MimicTaskPush(client()->rootTask() , jid().bare() , d->localAddress) ;
+	
+	client()->addExtension("mimic", Features(QString(MIMIC_NS)));
+#endif
 
 	emit connected ();
 }
@@ -1133,5 +1158,12 @@
 
 }
 
+#ifdef SUPPORT_MIMIC
+void JabberClient::startMimicWebcam( const QString & to, bool wantToReceive )
+{
+	d->mimic->startWebcam( d->jid.full() , to,  wantToReceive );
+}
+#endif
 
+
 #include "jabberclient.moc"
Index: protocols/jabber/Makefile.am
===================================================================
--- protocols/jabber/Makefile.am	(revision 614319)
+++ protocols/jabber/Makefile.am	(working copy)
@@ -1,3 +1,8 @@
+if include_msn_webcam
+WEBCAM = webcam
+WEBCAM_LIBS=webcam/libkopetejabberwebcam.la ../../libkopete/avdevice/libkopete_videodevice.la
+endif
+
 if include_jingle
 JINGLE=jingle
 JINGLE_LIBS=jingle/libkopetejabberjingle.la
@@ -5,7 +10,7 @@
 endif
 
 METASOURCES = AUTO
-SUBDIRS = ui icons libiris $(JINGLE) . kioslave
+SUBDIRS = ui icons libiris $(WEBCAM) $(JINGLE) . 
 AM_CPPFLAGS = $(KOPETE_INCLUDES) \
 	-I$(srcdir)/libiris/iris/include \
 	-I$(srcdir)/libiris/iris/xmpp-im \
@@ -14,6 +19,7 @@
 	-I$(srcdir)/libiris/cutestuff/util \
 	-I$(srcdir)/libiris/cutestuff/network \
 	-I$(srcdir)/ui \
+	-I$(srcdir)/webcam \
 	-I./ui \
 	$(all_includes) $(JINGLE_INCLUDES)
 
@@ -55,7 +61,7 @@
 	libiris/cutestuff/network/libcutestuff_network.la \
 	libiris/cutestuff/util/libcutestuff_util.la \
 	libjabberclient.la \
-	$(JINGLE_LIBS)
+	$(JINGLE_LIBS) $(WEBCAM_LIBS)
 
 service_DATA = kopete_jabber.desktop
 servicedir = $(kde_servicesdir)
Index: protocols/jabber/jabberchatsession.cpp
===================================================================
--- protocols/jabber/jabberchatsession.cpp	(revision 614319)
+++ protocols/jabber/jabberchatsession.cpp	(working copy)
@@ -62,13 +62,13 @@
 
 	mResource = jid.resource().isEmpty () ? resource : jid.resource ();
 	slotUpdateDisplayName ();
+	
+	setInstance(protocol->instance());
 
 #ifdef SUPPORT_JINGLE
 	KAction *jabber_voicecall = new KAction( i18n("Voice call" ), "voicecall", 0, members().getFirst(), SLOT(voiceCall ()), actionCollection(), "jabber_voicecall" );
 
-	setInstance(protocol->instance());
 	jabber_voicecall->setEnabled( false );
-
 	
 	Kopete::ContactPtrList chatMembers = members ();
 	if ( chatMembers.first () )
@@ -83,7 +83,32 @@
 	}
 
 #endif
+	
+#ifdef SUPPORT_MIMIC
+	if ( members().getFirst() )
+	{
+	
+		// Invite to receive webcam action
+		KAction *actionWebcamReceive=new KAction( i18n( "View Contact's Webcam" ), "webcamreceive",  0, members().getFirst(), SLOT(webcamReceive()), actionCollection(), "msnWebcamReceive" ) ;
+		actionWebcamReceive->setEnabled( false );
+		
+		//Send webcam action
+		KAction *actionWebcamSend=new KAction( i18n( "Send Webcam" ), "webcamsend",  0, members().getFirst(), SLOT(webcamSend()), actionCollection(), "msnWebcamSend" ) ;
+		actionWebcamSend->setEnabled( false );
+	
+	
+		// Check if the current contact support Voice calls, also honour lock by default.
+		// FIXME: we should use the active ressource
+		JabberResource *bestResource = account()->resourcePool()->  bestJabberResource( static_cast<JabberBaseContact*>(members().getFirst())->rosterItem().jid() );
+		if( bestResource && bestResource->features().list().contains("http://kopete.kde.org/protocol/mimic") )
+		{
+			actionWebcamReceive->setEnabled( true );
+			actionWebcamSend->setEnabled( true );
+		}
+	}
 
+#endif
+
  new KAction( i18n( "Send File" ), "attach", 0, this, SLOT( slotSendFile() ), actionCollection(), "jabberSendFile" );
 
 	setXMLFile("jabberchatui.rc");
