[iris] port/rebase kopete patches (kudos to kkofler)

Rex Dieter rdieter at fedoraproject.org
Thu Feb 14 13:25:30 UTC 2013


commit cc935eda4d64fcd0f7719ea7cf1acff1f0ad836d
Author: Rex Dieter <rdieter at math.unl.edu>
Date:   Thu Feb 14 07:25:17 2013 -0600

    port/rebase kopete patches (kudos to kkofler)

 iris-1.0.0-003_case_insensitive_jid.patch        |   13 +
 iris-1.0.0-009_filetransferpreview.patch         |  134 +
 iris-1.0.0-014_fix_semicolons.patch              |   22 +
 iris-1.0.0-023_jingle-1.patch                    | 3356 +++++++++++++++++++++
 iris-1.0.0-023_jingle.patch                      | 3393 ++++++++++++++++++++++
 iris-1.0.0-024_fix_semicolons_and_iterator.patch |  299 ++
 iris-1.0.0-027_add_socket_access_function.patch  |  121 +
 iris-1.0.0-030_xep_0115_hash_attribute.patch     |  138 +
 iris-1.0.0-install_jingle.patch                  |   14 +
 iris.spec                                        |   27 +-
 10 files changed, 7514 insertions(+), 3 deletions(-)
---
diff --git a/iris-1.0.0-003_case_insensitive_jid.patch b/iris-1.0.0-003_case_insensitive_jid.patch
new file mode 100644
index 0000000..0216c8a
--- /dev/null
+++ b/iris-1.0.0-003_case_insensitive_jid.patch
@@ -0,0 +1,13 @@
+diff -Nur iris-1.0.0/src/xmpp/jid/jid.cpp iris-1.0.0-003_case_insensitive_jid/src/xmpp/jid/jid.cpp
+--- iris-1.0.0/src/xmpp/jid/jid.cpp	2011-03-02 10:37:32.000000000 +0100
++++ iris-1.0.0-003_case_insensitive_jid/src/xmpp/jid/jid.cpp	2013-02-13 19:48:34.000000000 +0100
+@@ -274,6 +274,9 @@
+ 		b = d;
+ 	else
+ 		b = n + '@' + d;
++	
++	b=b.toLower(); // JID are not case sensitive
++	
+ 	if(r.isEmpty())
+ 		f = b;
+ 	else
diff --git a/iris-1.0.0-009_filetransferpreview.patch b/iris-1.0.0-009_filetransferpreview.patch
new file mode 100644
index 0000000..9142055
--- /dev/null
+++ b/iris-1.0.0-009_filetransferpreview.patch
@@ -0,0 +1,134 @@
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/filetransfer.cpp iris-1.0.0-009_filetransferpreview/src/xmpp/xmpp-im/filetransfer.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/filetransfer.cpp	2011-02-24 19:05:06.000000000 +0100
++++ iris-1.0.0-009_filetransferpreview/src/xmpp/xmpp-im/filetransfer.cpp	2013-02-13 19:54:58.000000000 +0100
+@@ -58,6 +58,7 @@
+ 	qlonglong size;
+ 	qlonglong sent;
+ 	QString desc;
++	QString preview;
+ 	bool rangeSupported;
+ 	qlonglong rangeOffset, rangeLength, length;
+ 	QString streamType;
+@@ -129,19 +130,20 @@
+ 	d->proxy = proxy;
+ }
+ 
+-void FileTransfer::sendFile(const Jid &to, const QString &fname, qlonglong size, const QString &desc)
++void FileTransfer::sendFile(const Jid &to, const QString &fname, qlonglong size, const QString &desc, const QString& preview)
+ {
+ 	d->state = Requesting;
+ 	d->peer = to;
+ 	d->fname = fname;
+ 	d->size = size;
+ 	d->desc = desc;
++	d->preview = preview;
+ 	d->sender = true;
+ 	d->id = d->m->link(this);
+ 
+ 	d->ft = new JT_FT(d->m->client()->rootTask());
+ 	connect(d->ft, SIGNAL(finished()), SLOT(ft_finished()));
+-	d->ft->request(to, d->id, fname, size, desc, d->m->streamPriority() );
++	d->ft->request(to, d->id, fname, size, desc, d->m->streamPriority(), preview);
+ 	d->ft->go(true);
+ }
+ 
+@@ -194,6 +196,12 @@
+ 	return d->desc;
+ }
+ 
++
++QString XMPP::FileTransfer::preview() const
++{
++	return d->preview;
++}
++
+ bool FileTransfer::rangeSupported() const
+ {
+ 	return d->rangeSupported;
+@@ -347,6 +355,7 @@
+ 	d->fname = req.fname;
+ 	d->size = req.size;
+ 	d->desc = req.desc;
++	d->preview = req.preview;
+ 	d->rangeSupported = req.rangeSupported;
+ 	d->streamType = streamType;
+ }
+@@ -548,7 +557,7 @@
+ }
+ 
+ void JT_FT::request(const Jid &to, const QString &_id, const QString &fname,
+-					qlonglong size, const QString &desc, const QStringList &streamTypes)
++					qlonglong size, const QString &desc, const QStringList &streamTypes, const QString& preview)
+ {
+ 	QDomElement iq;
+ 	d->to = to;
+@@ -567,6 +576,12 @@
+ 		de.appendChild(doc()->createTextNode(desc));
+ 		file.appendChild(de);
+ 	}
++	if(!preview.isEmpty()) {
++		QDomElement pr = doc()->createElement("preview");
++		pr.setAttribute("xmlns", "http://kopete.kde.org/protocol/file-preview");
++		pr.appendChild(doc()->createTextNode(preview));
++		file.appendChild(pr);
++	}
+ 	QDomElement range = doc()->createElement("range");
+ 	file.appendChild(range);
+ 	si.appendChild(file);
+@@ -800,6 +815,11 @@
+ 	QDomElement de = file.elementsByTagName("desc").item(0).toElement();
+ 	if(!de.isNull())
+ 		desc = de.text();
++	
++	QString preview;
++	QDomElement pr = file.elementsByTagName("preview").item(0).toElement();
++	if(!pr.isNull())
++		preview= pr.text();
+ 
+ 	bool rangeSupported = false;
+ 	QDomElement range = file.elementsByTagName("range").item(0).toElement();
+@@ -831,6 +851,7 @@
+ 	r.fname = fname;
+ 	r.size = size;
+ 	r.desc = desc;
++	r.preview = preview;
+ 	r.rangeSupported = rangeSupported;
+ 	r.streamTypes = streamTypes;
+ 
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/filetransfer.h iris-1.0.0-009_filetransferpreview/src/xmpp/xmpp-im/filetransfer.h
+--- iris-1.0.0/src/xmpp/xmpp-im/filetransfer.h	2011-02-24 19:05:06.000000000 +0100
++++ iris-1.0.0-009_filetransferpreview/src/xmpp/xmpp-im/filetransfer.h	2013-02-13 19:48:35.000000000 +0100
+@@ -55,7 +55,7 @@
+ 		void setProxy(const Jid &proxy);
+ 
+ 		// send
+-		void sendFile(const Jid &to, const QString &fname, qlonglong size, const QString &desc);
++		void sendFile(const Jid &to, const QString &fname, qlonglong size, const QString &desc, const QString& preview=QString());
+ 		qlonglong offset() const;
+ 		qlonglong length() const;
+ 		int dataSizeNeeded() const;
+@@ -66,6 +66,7 @@
+ 		QString fileName() const;
+ 		qlonglong fileSize() const;
+ 		QString description() const;
++		QString preview() const;
+ 		bool rangeSupported() const;
+ 		void accept(qlonglong offset=0, qlonglong length=0);
+ 
+@@ -144,7 +145,7 @@
+ 		JT_FT(Task *parent);
+ 		~JT_FT();
+ 
+-		void request(const Jid &to, const QString &id, const QString &fname, qlonglong size, const QString &desc, const QStringList &streamTypes);
++		void request(const Jid &to, const QString &id, const QString &fname, qlonglong size, const QString &desc, const QStringList &streamTypes, const QString &preview=QString());
+ 		qlonglong rangeOffset() const;
+ 		qlonglong rangeLength() const;
+ 		QString streamType() const;
+@@ -164,6 +165,7 @@
+ 		QString fname;
+ 		qlonglong size;
+ 		QString desc;
++		QString preview;
+ 		bool rangeSupported;
+ 		QStringList streamTypes;
+ 	};
diff --git a/iris-1.0.0-014_fix_semicolons.patch b/iris-1.0.0-014_fix_semicolons.patch
new file mode 100644
index 0000000..e1fe9a2
--- /dev/null
+++ b/iris-1.0.0-014_fix_semicolons.patch
@@ -0,0 +1,22 @@
+diff -Nur iris-1.0.0/src/xmpp/xmpp-core/parser.cpp iris-1.0.0-014_fix_semicolons/src/xmpp/xmpp-core/parser.cpp
+--- iris-1.0.0/src/xmpp/xmpp-core/parser.cpp	2008-08-19 01:03:07.000000000 +0200
++++ iris-1.0.0-014_fix_semicolons/src/xmpp/xmpp-core/parser.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -547,7 +547,7 @@
+ 		QList<Parser::Event*> eventList;
+ 		bool needMore;
+ 	};
+-};
++}
+ 
+ 
+ //----------------------------------------------------------------------------
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_xmlcommon.cpp iris-1.0.0-014_fix_semicolons/src/xmpp/xmpp-im/xmpp_xmlcommon.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_xmlcommon.cpp	2008-06-02 18:58:17.000000000 +0200
++++ iris-1.0.0-014_fix_semicolons/src/xmpp/xmpp-im/xmpp_xmlcommon.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -561,5 +561,5 @@
+ 	}
+ }
+ 
+-};
++}
+ 
diff --git a/iris-1.0.0-023_jingle-1.patch b/iris-1.0.0-023_jingle-1.patch
new file mode 100644
index 0000000..ee905f8
--- /dev/null
+++ b/iris-1.0.0-023_jingle-1.patch
@@ -0,0 +1,3356 @@
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglecontent.cpp iris-1.0.0-023_jingle/src/xmpp/jingle/jinglecontent.cpp
+--- iris-1.0.0/src/xmpp/jingle/jinglecontent.cpp	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglecontent.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,509 @@
++/*
++ * jinglecontent.cpp - Jingle content
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#include "jinglecontent.h"
++
++#include "jinglesession.h"
++
++#include <QTimer>
++#include <QDomElement>
++#include <QUdpSocket>
++
++//----------------------
++// JingleContent
++//----------------------
++
++using namespace XMPP;
++
++
++class JingleContent::Private
++{
++public:
++	QList<QDomElement> payloads; // My payloads.
++	QList<QDomElement> rPayloads; // Responder's payloads.
++	QDomElement bestPayload;
++
++	QDomElement transport;
++	QList<QDomElement> candidates;
++	QString creator;
++	QString name;
++	QString descriptionNS;
++	//The application will access this socket directly, Iris has not to deal with RTP.
++	QUdpSocket *inSocket; //Currently, this is the IN raw-udp socket for this content.
++	QUdpSocket *outSocket; //Currently, this is the OUT raw-udp socket for this content.
++	bool sending;
++	bool receiving;
++	Type type;
++	bool isInitiator;
++	QTimer *outTimer;
++	int tries;
++};
++
++JingleContent::JingleContent()
++: d(new Private())
++{
++	qDebug() << "Creating JingleContent";
++	d->sending = false;
++	d->receiving = false;
++	d->inSocket = 0L;
++	d->outSocket = 0L;
++	d->isInitiator = false;
++	d->tries = 0;
++}
++
++JingleContent::~JingleContent()
++{
++	//delete d->inSocket;
++	//delete d->outSocket;
++	delete d;
++}
++
++QDomElement JingleContent::bestPayload()
++{
++	if (d->bestPayload.isNull())
++	{
++		//Trying to update the best payload.
++		d->bestPayload = bestPayload(d->rPayloads, d->payloads);
++	}
++	return d->bestPayload;
++}
++
++void JingleContent::addCandidate(const QDomElement& c)
++{
++	d->candidates << c;
++}
++
++void JingleContent::addPayloadType(const QDomElement& pl)
++{
++	d->payloads << pl;
++}
++
++void JingleContent::addPayloadTypes(const QList<QDomElement>& pl)
++{
++	d->payloads << pl;
++}
++
++void JingleContent::setPayloadTypes(const QList<QDomElement>& pl)
++{
++	d->payloads.clear();
++	d->payloads = pl;
++}
++
++void JingleContent::setTransport(const QDomElement& t)
++{
++	d->transport = t;
++}
++
++QList<QDomElement> JingleContent::payloadTypes() const
++{
++	return d->payloads;
++}
++
++QDomElement JingleContent::transport() const
++{
++	return d->transport;
++}
++
++void JingleContent::setCreator(const QString& c)
++{
++	d->creator = c;
++}
++
++void JingleContent::setName(const QString& n)
++{
++	d->name = n;
++}
++
++void JingleContent::setDescriptionNS(const QString& desc)
++{
++	d->descriptionNS = desc;
++}
++
++void JingleContent::fromElement(const QDomElement& e)
++{
++	// FIXME:tag order may not always be the same !!!
++	if (e.tagName() != "content")
++		return;
++	d->creator = e.attribute("creator");
++	d->name = e.attribute("name");
++	QDomElement desc = e.firstChildElement();
++	d->descriptionNS = desc.attribute("xmlns");
++	d->type = stringToType(desc.attribute("media"));
++	QDomElement payload = desc.firstChildElement();
++	// This content is created from XML data, that means that it comes from the outside.
++	// So, pyloads are added as responder payloads
++	QList<QDomElement> payloads;
++	while (!payload.isNull())
++	{
++		payloads << payload;
++		payload = payload.nextSiblingElement();
++	}
++	setResponderPayloads(payloads);
++
++	QDomElement transport = desc.nextSiblingElement();
++	d->transport = transport;
++}
++
++QDomElement JingleContent::contentElement()
++{
++	// Create the QDomElement which has to be returned.
++	QDomDocument doc("");
++	
++	QDomElement content = doc.createElement("content");
++	content.setAttribute("creator", d->creator);
++	content.setAttribute("name", d->name);
++	content.setAttribute("sender", "both"); //Setting to default currently, change it !
++	
++	QDomElement description = doc.createElement("description");
++	description.setAttribute("xmlns", d->descriptionNS);
++	description.setAttribute("media", typeToString(d->type));
++
++	for (int i = 0; i < d->payloads.count(); i++)
++	{
++		description.appendChild(d->payloads.at(i));
++	}
++	content.appendChild(description);
++	content.appendChild(d->transport);
++
++	return content;
++}
++
++QString JingleContent::name() const
++{
++	return d->name;
++}
++
++QString JingleContent::descriptionNS() const
++{
++	return d->descriptionNS;
++}
++
++void JingleContent::addTransportInfo(const QDomElement& e)
++{
++	QDomElement transport = e.firstChildElement();
++	if (transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++	{
++		if (d->transport.attribute("pwd") != transport.attribute("pwd"))
++		{
++			qDebug() << "Bad ICE Password !";
++			return;
++		}
++		
++		if (d->transport.attribute("ufrag") != transport.attribute("ufrag"))
++		{
++			qDebug() << "Bad ICE User Fragment !";
++			return;
++		}
++		QDomElement child = transport.firstChildElement();
++		//FIXME:Is it possible to have more than one candidate per transport-info ?
++		//	See Thread "Jingle: multiple candidates per transport-info?" on xmpp-standards.
++		if (child.tagName() == "candidate")
++		{
++			// Just adding the Xml Element.
++			d->candidates << child;
++		}
++	}
++	else if (transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++	{
++		qDebug() << "Adding responder's candidates and connecting to it";
++		d->candidates << transport.firstChildElement();
++		//TODO : Start connection to this candidate.
++		//WARNING : as Jingle specification is not clear,
++		//	    the connexion will be considered as established
++		//	    even without receiving the "received" informational
++		//	    message.
++		startSending(QHostAddress(transport.firstChildElement().attribute("ip")),
++			     transport.firstChildElement().attribute("port").toInt());
++		
++	}
++}
++
++/*FIXME:this as no sense, this content is for RAW UDP only*/
++QString JingleContent::iceUdpPassword()
++{
++	if (d->transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++		return d->transport.attribute("pwd");
++	return "";
++}
++
++/*FIXME:this as no sense, this content is for RAW UDP only*/
++QString JingleContent::iceUdpUFrag()
++{
++	if (d->transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++		return d->transport.attribute("ufrag");
++	return "";
++}
++
++void JingleContent::createUdpInSocket()
++{
++	if (d->transport.attribute("xmlns") != NS_JINGLE_TRANSPORTS_RAW)
++		return;
++	qDebug() << "JingleContent::createUdpInSocket()";
++	
++	if (!d->inSocket)
++		d->inSocket = new QUdpSocket();
++	
++	QHostAddress address(d->transport.firstChildElement().attribute("ip"));
++	int port = d->transport.firstChildElement().attribute("port").toInt();
++	qDebug() << "Bind socket to" << address << ":" << port;
++	if (d->inSocket->bind(/*address, */port))
++		qDebug() << "Socket bound to" << /*address.toString() << ":" <<*/ port;
++	
++	connect(d->inSocket, SIGNAL(readyRead()), this, SLOT(slotRawUdpDataReady()));
++	//emit inSocketReady(); --> also no need of this.
++}
++
++void JingleContent::slotRawUdpDataReady()
++{
++	qDebug() << "slotRawUdpDataReady() :: Data arrived on the socket.";
++	emit dataReceived();
++	setReceiving(true);
++	disconnect(sender(), SIGNAL(readyRead()), this, 0);
++}
++
++QUdpSocket *JingleContent::inSocket()
++{
++	qDebug() << "Getting IN socket from content" << name();
++	return d->inSocket;
++}
++
++QUdpSocket *JingleContent::outSocket()
++{
++	qDebug() << "Getting OUT socket from content" << name();
++	return d->outSocket;
++}
++
++bool JingleContent::sending()
++{
++	return d->sending;
++}
++
++void JingleContent::setSending(bool s)
++{
++	if (d->sending == s)
++		return;
++	d->sending = s;
++	
++	// We do not need to try sending anymore, we have proof that data sending is OK.
++	d->outTimer->stop();
++	delete d->outTimer;
++
++	// If we are also receiving, that's ok, this content is established.
++	if (d->sending && d->receiving)
++	{
++		qDebug() << "setSending : emit established() SIGNAL";
++		emit established();
++	}
++}
++
++bool JingleContent::receiving()
++{
++	return d->receiving;
++}
++
++void JingleContent::setReceiving(bool r)
++{
++	if (d->receiving == r)
++		return;
++	d->receiving = r;
++	if (d->sending && d->receiving)
++	{
++		qDebug() << "setReceiving : emit established() SIGNAL";
++		emit established();
++	}
++}
++
++void JingleContent::startSending()
++{
++	QHostAddress address(transport().firstChildElement().attribute("ip"));
++	int port = transport().firstChildElement().attribute("port").toInt();
++	startSending(address, port);
++}
++
++void JingleContent::startSending(const QHostAddress& address, int port)
++{
++	//This correspond to the trying phase.
++	//Create udp OUT socket
++	if (!d->outSocket)
++		d->outSocket = new QUdpSocket();
++	d->outSocket->connectToHost(address, port);
++	//emit outSocketReady(); --> This signal has no sense anymore, we must prepare rtp sessions when the sockets are both ready.
++	
++	qDebug() << "Sending data to" << address.toString() << ":" << port;
++	//We will start sending "SYN" every 5 seconds for 1 minute until we receive a received informationnal message.
++	slotTrySending();
++	d->outTimer = new QTimer();
++	d->outTimer->setInterval(5000);
++	connect(d->outTimer, SIGNAL(timeout()), this, SLOT(slotTrySending()));
++	//setSending(true); --> set it when the received informationnal message has been received.
++}
++
++void JingleContent::slotTrySending()
++{
++	d->tries++;
++	if (d->tries == 13)
++	{
++		//This content cannot connect, what do we do ?
++		d->outTimer->stop();
++		qDebug() << "JingleContent::slotTrySending : Unable to establish the connection for content" << name();
++	}
++
++	d->outSocket->write(QByteArray("SYN"));
++}
++
++QList<QDomElement> JingleContent::candidates() const
++{
++	return d->candidates;
++}
++
++QString JingleContent::creator() const
++{
++	return d->creator;
++}
++
++void JingleContent::bind(const QHostAddress& address, int port)
++{
++	qDebug() << "Trying to bind socket to" << address.toString() << ":" << port;
++	if (!d->inSocket)
++		d->inSocket = new QUdpSocket();
++	if (d->inSocket->bind(address, port))
++		qDebug() << "Socket bound to" << address.toString() << ":" << port;
++	
++	connect(d->inSocket, SIGNAL(readyRead()), this, SLOT(slotRawUdpDataReady()));
++	
++	//emit inSocketReady();
++}
++
++JingleContent& JingleContent::operator=(const JingleContent &other)
++{
++	d->payloads = other.payloadTypes();
++	d->transport = other.transport();
++	d->candidates = other.candidates();
++	d->creator = other.creator();
++	d->name = other.name();
++	d->descriptionNS = other.descriptionNS();
++	
++	return *this;
++}
++
++void JingleContent::setType(JingleContent::Type t)
++{
++	d->type = t;
++}
++
++JingleContent::Type JingleContent::type() const
++{
++	return d->type;
++}
++
++QString JingleContent::typeToString(JingleContent::Type t)
++{
++	switch(t)
++	{
++	case Video :
++		return "video";
++	case Audio :
++		return "audio";
++	case FileTransfer :
++		return "file transfer";
++	default:
++		return "unknown";
++	}
++}
++
++void JingleContent::setResponderPayloads(const QList<QDomElement>& payloads)
++{
++	qDebug() << "*******Setting responder payloads**********";
++	d->rPayloads = payloads;
++	if (d->payloads.count() != 0) //No, if payloads is empty, we should get the list from the supported payloads. Actually, those payloads should be always set when creating the content.
++	{
++		//Store the best payload to use for this content.
++		//The application will just have to get it from this content.
++		d->bestPayload = bestPayload(d->rPayloads, d->payloads);
++	}
++}
++
++QList<QDomElement> JingleContent::responderPayloads() const
++{
++	return d->rPayloads;
++}
++
++JingleContent::Type JingleContent::stringToType(const QString& s)
++{
++	if (s == "video")
++		return Video;
++	else if (s == "audio")
++		return Audio;
++	else if (s == "file transfer")
++		return FileTransfer;
++	else
++		return Unknown;
++}
++
++QDomElement JingleContent::bestPayload(const QList<QDomElement>& payload1, const QList<QDomElement>& payload2)
++{
++	//FIXME : this is not the best algorithm to determine which one is the better.
++	// |-------|
++	// | a | c |
++	// +---+---+
++	// | b | b |
++	// +---+---+
++	// | d | e |
++	// +---+---+
++	// | c | a |
++	// |-------|
++	//  --> In that case, payload a will be chosen but payload b would be the best choice.
++	for (int i = 0; i < payload1.count(); i++)
++	{
++		for (int j = 0; j < payload2.count(); j++)
++		{
++			if (samePayload(payload1[i], payload2[j]))
++				return payload1[i];
++		}
++	}
++	qDebug() << "Returns QDomElement !";
++	return QDomElement();
++}
++
++bool JingleContent::samePayload(const QDomElement& p1, const QDomElement& p2)
++{
++	// Checking payload-type attributes
++	if (!p1.hasAttribute("id") || !p2.hasAttribute("id"))
++		return false;
++	if (p1.attribute("id") != p2.attribute("id"))
++		return false;
++	int id = p1.attribute("id").toInt();
++	if ((id >= 96) && (id <= 127)) //dynamic payloads, "name" attribute must be there
++	{
++		if (!p1.hasAttribute("name") || !p2.hasAttribute("name"))
++			return false;
++		if (p1.attribute("name") != p2.attribute("name"))
++			return false;
++	}
++	if (p1.hasAttribute("channels") && p2.hasAttribute("channels"))
++		if (p1.attribute("channels") != p2.attribute("channels"))
++			return false;
++	if (p1.hasAttribute("clockrate") && p2.hasAttribute("clockrate"))
++		if (p1.attribute("clockrate") != p2.attribute("clockrate"))
++			return false;
++	// Parameters are informative, even if they differ, the payload is stil the same.
++	qDebug() << "Payloads are the same.";
++	return true;
++}
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglecontent.h iris-1.0.0-023_jingle/src/xmpp/jingle/jinglecontent.h
+--- iris-1.0.0/src/xmpp/jingle/jinglecontent.h	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglecontent.h	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,211 @@
++/*
++ * jinglecontent.cpp - Jingle content
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++#ifndef JINGLE_CONTENT_H
++#define JINGLE_CONTENT_H
++
++#include <QObject>
++
++#include "im.h"
++
++class QHostAddress;
++class QDomElement;
++class QUdpSocket;
++namespace XMPP
++{
++	/*
++	 * This class contains all information about a particular content in a jingle session.
++	 * It also has the socket that will be used for streaming.
++	 */
++	//This is the Raw-udp jingle content.
++	class JingleContent : public QObject
++	{
++		Q_OBJECT
++	public:
++		JingleContent();
++		~JingleContent();
++
++		/**
++		 * Defines the content type, this represesent the media attribute.
++		 */
++		enum Type {
++			Audio = 0,
++			Video,
++			FileTransfer,
++			Unknown
++		};
++
++		/*
++		 * Adds a payload type to this content.
++		 */
++		void addPayloadType(const QDomElement&);
++		
++		/*
++		 * Adds a payload type list to this content.
++		 */
++		void addPayloadTypes(const QList<QDomElement>&);
++
++		/*
++		 * Overwrite the current payload types list with this one.
++		 */
++		void setPayloadTypes(const QList<QDomElement>&);
++
++		/*
++		 * Sets the transport for this content.
++		 */
++		void setTransport(const QDomElement&);
++
++		/*
++		 * Set the content type, this will set the "media" attribute of
++		 * the content tag in the stanza.
++		 */
++		void setType(Type);
++
++		/*
++		 * Gets the type of this content.
++		 */
++		Type type() const;
++
++		/*
++		 * Set the creator of this content, the creator only accept 2 values :
++		 * 	* initiator
++		 * 	* responder
++		 * TODO:An enum should be created to avoid confusion
++		 */
++		void setCreator(const QString&);
++		
++		/*
++		 * Set this content's name
++		 */
++		void setName(const QString&);
++
++		/*
++		 * Set this content description namespace.
++		 * The only one supported currently is
++		 * 	NS
++		 */
++		void setDescriptionNS(const QString&);
++
++		/*
++		 * Returns the payload type list. those payloads are
++		 * our payloads if in Pending state or the content
++		 * used payloads if in Active state. (TODO)
++		 */
++		QList<QDomElement> payloadTypes() const;
++
++		/*
++		 * Returns the transport XML element for this content.
++		 */
++		QDomElement transport() const;
++
++		/*
++		 * Fill this content from a QDomElement.
++		 * The payloads in this QDomElement will be considered as the responder's
++		 * TODO:add an argument to tell the method if those payloads are our's or
++		 * responder's payloads.
++		 */
++		void fromElement(const QDomElement&);
++
++		/*
++		 * Return a QDomElement with the content element and all it's children
++		 * so it's ready to be sent.
++		 */
++		QDomElement contentElement();
++
++		/*
++		 * Returns a list with the available candidates for this content.
++		 * TODO:should return the used candidate when in Active state.
++		 */
++		QList<QDomElement> candidates() const;
++
++		/*
++		 * Adds a candidate to this content. Doing so will add this content(s)
++		 * to the transport when calling contentElement()
++		 */
++		void addCandidate(const QDomElement&);
++		
++		/*
++		 * Adds transport info (mostly a candidate). Doing so will try to
++		 * connect to this candidate.
++		 */
++		void addTransportInfo(const QDomElement&);
++		void createUdpInSocket();
++		
++		QString creator() const;
++		QString name() const;
++		QString descriptionNS() const;
++		QString iceUdpPassword();
++		QString iceUdpUFrag();
++		QUdpSocket *inSocket();
++		QUdpSocket *outSocket();
++		bool sending();
++		void setSending(bool);
++		bool receiving();
++		void setReceiving(bool);
++
++		void startSending();
++		void startSending(const QHostAddress&, int);
++
++		void bind(const QHostAddress&, int);
++		
++		JingleContent& operator=(const JingleContent&);
++		
++		QString typeToString(Type);
++		Type stringToType(const QString& s);
++
++		void setResponderPayloads(const QList<QDomElement>&);
++		QList<QDomElement> responderPayloads() const;
++
++		QDomElement bestPayload();
++
++	public slots:
++		void slotRawUdpDataReady();
++
++		void slotTrySending();
++
++	signals:
++
++		// Emitted when the content is ready to send data to try to connect.
++		void needData(XMPP::JingleContent*);
++		
++		// Emitted when the IN socket is ready to receive data (it is bound).
++		// Can be used to prepare a rtp session with the socket.
++		void inSocketReady();
++		
++		// Emitted when the OUT socket is ready to send data (it is connected).
++		// Can be used to prepare a rtp session with the socket.
++		void outSocketReady();
++
++		/**
++		 * Emitted when sending and receiving streams have been established for this content 
++		 */
++		void established();
++
++		void dataReceived();
++
++	private:
++		class Private;
++		Private *d;
++		
++		QDomElement bestPayload(const QList<QDomElement>&, const QList<QDomElement>&);
++		bool samePayload(const QDomElement&, const QDomElement&);
++	};
++}
++
++#endif
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglesession.cpp iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesession.cpp
+--- iris-1.0.0/src/xmpp/jingle/jinglesession.cpp	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesession.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,665 @@
++/*
++ * jinglesession.cpp - Jingle session
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#include <QString>
++#include <QUdpSocket>
++
++#include "jinglesession.h"
++#include "jinglesessionmanager.h"
++
++using namespace XMPP;
++
++static QString genSid()
++{
++	QString s;
++	int id_seed = rand() % 0xffff;
++	s.sprintf("a%x", id_seed);
++	return s;
++}
++
++class JingleSession::Private
++{
++public:
++	Jid to;
++	QList<JingleContent*> contents;
++	Task *rootTask;
++	JingleSessionManager *jingleSessionManager;
++	QString sid;
++	QString initiator;
++	State state;
++	QStringList contentsToRemove;
++	QStringList transports;
++	bool responderTrying;
++	QList<JT_JingleAction*> actions;
++	bool allContentsConnected;
++	bool userAcceptedSession;
++};
++
++JingleSession::JingleSession(Task *t, const Jid &j)
++: d(new Private)
++{
++	qDebug() << "Creating XMPP::JingleSession";
++	d->to = j;
++	d->rootTask = t;
++	d->jingleSessionManager = t->client()->jingleSessionManager();
++	d->state = Pending;
++	d->responderTrying = false;
++	d->allContentsConnected = false;
++	d->userAcceptedSession = false;
++}
++
++JingleSession::~JingleSession()
++{
++	delete d;
++}
++
++void JingleSession::addContent(JingleContent *c)
++{
++	d->contents << c;
++	connect(c, SIGNAL(dataReceived()), this, SLOT(slotReceivingData()));
++	if (initiator() != d->rootTask->client()->jid().full())
++		connect(c, SIGNAL(established()), this, SLOT(slotContentConnected())); //Only do that if we are not the initiator.
++}
++
++void JingleSession::addContents(const QList<JingleContent*>& l)
++{
++	for (int i = 0; i < l.count(); i++)
++	{
++		d->contents << l[i];
++		connect(l[i], SIGNAL(dataReceived()), this, SLOT(slotReceivingData()));
++		if (initiator() != d->rootTask->client()->jid().full())
++			connect(l[i], SIGNAL(established()), this, SLOT(slotContentConnected()));
++	}
++}
++
++Jid JingleSession::to() const
++{
++	return d->to;
++}
++
++QList<JingleContent*> JingleSession::contents() const
++{
++	return d->contents;
++}
++
++void JingleSession::start()
++{
++	// Generate session ID
++	d->sid = genSid();
++
++	/*qDebug() << "There are" << contents().count() << "contents : ";
++	for (int i = 0; i < contents().count(); i++)
++	{
++		qDebug() << i << ":";
++		qDebug() << d->rootTask->client()->stream().xmlToString(contents()[i]->contentElement(), true);
++	}*/
++
++	JT_JingleAction *iAction = new JT_JingleAction(d->rootTask);
++	d->actions << iAction;
++	iAction->setSession(this);
++	connect(iAction, SIGNAL(finished()), this, SLOT(slotAcked()));
++	iAction->initiate();
++	iAction->go(true);
++	/*for (int i = 0; i < contents().count(); i++)
++	{
++		if (contents()[i]->transport().attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++		{
++			qDebug() << "Create IN socket for" << contents()[i]->name();
++			//qDebug("Content Adress : %x\n", (unsigned int) contents()[i]);
++			//contents()[i]->createUdpInSocket(); --> should be done by the JT_JingleAction::initiate().
++		}
++	}*/
++}
++
++void JingleSession::slotAcked()
++{
++	//Should be autamtically deleted by Iris.
++	/*if (!sender())
++	{
++		qDebug() << "Sender is NULL !";
++		return;
++	}
++	deleteAction(static_cast<JT_JingleAction*>(sender()));*/
++}
++
++void JingleSession::deleteAction(JT_JingleAction* a)
++{
++	//Don't delete tasks, iris will take care of it.
++	/*for (int i = 0; i < d->actions.count(); i++)
++	{
++		if (d->actions[i] == a)
++		{
++			delete d->actions.takeAt(i);
++			break;
++		}
++	}*/
++}
++
++void JingleSession::slotContentConnected()
++{
++	qDebug() << "---------------- void JingleSession::slotContentConnected() : called";
++	bool allOk = true;
++	// Checking if all contents are connected.
++	for (int i = 0; i < contents().count(); i++)
++	{
++		if (!contents()[i]->sending() || !contents()[i]->receiving())
++		{
++			allOk = false;
++			break;
++		}
++	}
++	
++	if (!allOk)
++	{
++		qDebug() << "Not All ok !!! --> Not switching to ACTIVE state.";
++		disconnect(sender(), 0, this, 0);
++		return;
++	}
++	else
++		d->allContentsConnected = true;
++	
++	if (!d->userAcceptedSession)
++	{
++		qDebug() << "User did not accept the session yet.";
++		disconnect(sender(), 0, this, 0);
++		return;
++	}
++	
++	/*qDebug() << initiator() << "=?=" << d->rootTask->client()->jid().full();
++	if (initiator() == d->rootTask->client()->jid().full())
++	{
++		// In this case, we must not send session-accept and wait for it.
++		qDebug() << "I'm the initiator, it's not me who must accept the session.";
++		disconnect(sender(), 0, this, 0);
++		return;
++	}*/
++
++	acceptSession();
++
++	disconnect(sender(), 0, this, 0);
++}
++
++void JingleSession::sessionAccepted(const QDomElement& x)
++{
++	qDebug() << "void JingleSession::sessionAccepted(const QDomElement& x) called";
++	QDomElement content = x.firstChildElement();
++	
++	while (!content.isNull())
++	{
++		JingleContent *c = contentWithName(content.attribute("name"));
++		QList<QDomElement> payloads;
++		QDomElement pType = content.firstChildElement().firstChildElement();
++		//		    content    description         payload-type
++		while (!pType.isNull())
++		{
++			payloads << pType;
++			pType = pType.nextSiblingElement();
++		}
++		c->setResponderPayloads(payloads);
++		qDebug() << "Best payload name :" << c->bestPayload().attribute("name");
++		content = content.nextSiblingElement();
++	}
++	d->state = Active;
++
++	qDebug() << "Ok, we switched to ACTIVE state, starting to stream.";
++	
++	emit stateChanged();
++}
++
++void JingleSession::slotSessionAcceptAcked()
++{
++	d->state = Active;
++
++	if (sender())
++		deleteAction(static_cast<JT_JingleAction*>(sender()));
++	qDebug() << "Ok, we switched to ACTIVE state, starting to stream.";
++	emit stateChanged();
++}
++
++void JingleSession::slotRawUdpDataReady()
++{/*
++	JingleContent *content = (JingleContent*) sender();
++	//qDebug("Content Adress : %x\n", (unsigned int) content);
++	if (content == NULL)
++	{
++		qDebug() << "Null Jingle content, there is a problem";
++		return;
++	}
++	if (d->state == Pending)
++	{
++		content->setReceiving(true);
++		// We check if each contents is receiving AND sending.
++		// In this case, the state can be changed to Active (should emit active() signal)
++		bool changeState = true;
++		for (int i = 0; i < contents().count(); i++)
++		{
++			if ((!contents()[i]->receiving()) || (!contents()[i]->sending()))
++			{
++				changeState = false;
++				break;
++			}
++		}
++		if (changeState)
++			d->state = Active;
++	}
++	QByteArray datagram;
++	QHostAddress address;
++	quint16 port;
++	datagram.resize(content->socket()->pendingDatagramSize());
++	content->socket()->readDatagram(datagram.data(), datagram.size(), &address, &port);
++	qDebug() << "Receiving data for content" << content->name() << "from" << address.toString() << ":" << port << ":";
++	qDebug() << datagram;
++
++	// Send "received" informationnal message. --> No, doesn't.
++	//JT_JingleAction *rAction = new JT_JingleAction(d->rootTask);
++	//connect(rAction, SIGNAL(finished()), this, SLOT(slotReceivedAcked()));
++	//rAction->setSession(this);
++	//rAction->received();
++*/
++}
++
++void JingleSession::acceptSession()
++{
++	qDebug() << "JingleSession::acceptSession() : called";
++
++	if (d->allContentsConnected)
++	{
++		//Accept session.
++		qDebug() << "Ok, all contents connected and session accepted by the user ! let's accept the session.";
++		// Create all contents to send in the session-accept.
++		QList<JingleContent*> contentList;
++		for (int i = 0; i < contents().count(); i++)
++		{
++			qDebug() << "setting right information in the content" << contents()[i]->name();
++			// First, set our supported payload-types.
++			JingleContent *c = new JingleContent();
++			c->setType(contents()[i]->type());
++			c->setPayloadTypes(c->type() == JingleContent::Audio ?
++						d->jingleSessionManager->supportedAudioPayloads() :
++						d->jingleSessionManager->supportedVideoPayloads());
++			c->setDescriptionNS(contents()[i]->descriptionNS());
++			c->setName(contents()[i]->name());
++			c->setCreator(contents()[i]->creator());
++			c->setTransport(contents()[i]->transport().cloneNode(false).toElement()); //We don't need the child nodes.
++			contentList << c;
++	
++			// Then, set the corresponding candidate for ICE-UDP (let's see later)
++			// TODO:implement me !
++		}
++	
++		qDebug() << "Sending session-accept action.";
++		JT_JingleAction *sAction = new JT_JingleAction(d->rootTask);
++		d->actions << sAction;
++		sAction->setSession(this);
++		connect(sAction, SIGNAL(finished()), this, SLOT(slotSessionAcceptAcked()));
++		sAction->sessionAccept(contentList);
++		sAction->go(true);
++	}
++	else
++	{
++		qDebug() << "d->allContentsConnected is FALSE !!!";
++	}
++
++	d->userAcceptedSession = true;
++}
++
++void JingleSession::acceptContent()
++{
++	//TODO:Implement me !
++	//JT_JingleAction *tAction = new JT_JingleAction(d->rootTask);
++	//tAction->setSession(this);
++	//tAction->contentAccept();
++}
++
++void JingleSession::removeContent(const QStringList& c)
++{
++	// Removing only existing contents.
++	for (int i = 0; i < c.count(); i++)
++	{
++		for (int j = 0; j < contents().count(); j++)
++		{
++			if (c.at(i) == contents()[j]->name())
++			{
++				d->contentsToRemove << c[i];
++			}
++		}
++	}
++	if (d->contentsToRemove.count() <= 0)
++		return;
++	
++	//d->contents.removeAt(i); //Or do it in the slotRemoveAcked() ?? --> Yes, we will remove all contents in d->contentsToRemove from d->contents when acked.
++	JT_JingleAction *rAction = new JT_JingleAction(d->rootTask);
++	d->actions << rAction;
++	rAction->setSession(this);
++	connect(rAction, SIGNAL(finished()), this, SLOT(slotRemoveAcked()));
++	rAction->removeContents(d->contentsToRemove);
++	rAction->go(true);
++}
++
++void JingleSession::removeContent(const QString& c) // Provided for convenience, may disappear.
++{
++/*
++ * From Jingle Specification : 
++ * A client MUST NOT return an error upon receipt of a 'content-remove' action for a content
++ * type that is received after a 'content-remove' action has been sent but before the action
++ * has been acknowledged by the peer. 
++ * 
++ * If the content-remove results in zero content types for the session, the entity that receives
++ * the content-remove SHOULD send a session-terminate action to the other party (since a session
++ * with no content types is void).
++ */
++	bool found = false;
++	//if (d->state != Active) /*FIXME:Should be if (d->state == Pending)*/
++	{
++		// FIXME:whatever the state is, the same thing will be done here...
++		// Checking if that content exists.
++		int i = 0;
++		for ( ; i < contents().count(); i++)
++		{
++			if (contents()[i]->name() == c)
++			{
++				found = true;
++				break;
++			}
++		}
++		if (!found)
++		{
++			qDebug() << "This content does not exists for this session (" << c << ")";
++			return;
++		}
++		JT_JingleAction *rAction = new JT_JingleAction(d->rootTask);
++		d->actions << rAction;
++		connect(rAction, SIGNAL(finished()), this, SLOT(slotRemoveAcked()));
++		rAction->setSession(this);
++		d->contentsToRemove << c;
++		rAction->removeContents(d->contentsToRemove);
++		rAction->go(true);
++	}
++}
++
++void JingleSession::slotRemoveAcked()
++{
++	JT_JingleAction *rAction = (JT_JingleAction*) sender();
++	if (rAction != 0)
++		deleteAction(static_cast<JT_JingleAction*>(sender()));
++	else
++		return;
++	// Remove contents from the d->contents
++	for (int i = 0; i < d->contentsToRemove.count(); i++)
++	{
++		for (int j = 0; j < contents().count(); j++)
++		{
++			if (d->contentsToRemove[i] == contents()[j]->name())
++			{
++				d->contents.removeAt(j);
++				break;
++			}
++		}
++	}
++	d->contentsToRemove.clear();
++
++	//else if (d->state == Active)
++	//	emit stopSending(d->contentsToRemove);
++}
++
++void JingleSession::ring()
++{
++	JT_JingleAction *rAction = new JT_JingleAction(d->rootTask);
++	d->actions << rAction;
++	connect(rAction, SIGNAL(finished()), this, SLOT(slotAcked()));
++	rAction->setSession(this);
++	rAction->ringing();
++	rAction->go(true);
++}
++
++void JingleSession::setSid(const QString& s)
++{
++	d->sid = s;
++}
++
++QString JingleSession::sid() const
++{
++	return d->sid;
++}
++
++void JingleSession::setInitiator(const QString& init)
++{
++	d->initiator = init;
++}
++
++void JingleSession::addContent(const QDomElement& content)
++{
++	JingleContent *c = new JingleContent();
++	c->fromElement(content);
++	d->contents << c;
++	
++	if (initiator() != d->rootTask->client()->jid().full())
++		connect(c, SIGNAL(established()), this, SLOT(slotContentConnected()));
++	connect(c, SIGNAL(dataReceived()), this, SLOT(slotReceivingData()));
++}
++
++void JingleSession::sessionTerminate(const JingleReason& r)
++{
++//FIXME:should Take an QDomElement as argument, the application should implement this
++//class itself and be able to return the right QDomElement when calling this method
++	JT_JingleAction *tAction = new JT_JingleAction(d->rootTask);
++	d->actions << tAction;
++	tAction->setSession(this);
++	connect(tAction, SIGNAL(finished()), this, SLOT(slotSessTerminated()));
++	tAction->terminate(r);
++	tAction->go(true);
++}
++
++QString JingleSession::initiator() const
++{
++	return d->initiator;
++}
++
++//TODO:maybe change the name of this function.
++void JingleSession::startNegotiation()
++{
++	/* TODO:
++	 * 	For each transport in each contents, I must send all possible candidates.
++	 * 	Those candidates can be found without the help of the application.
++	 */
++	qDebug() << "Start Negotiation : ";
++	for (int i = 0; i < d->contents.count(); i++)
++	{
++		if (d->contents[i]->transport().attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++		{
++			qDebug() << "    ICE-UDP";
++			sendIceUdpCandidates();
++		}
++		else if (d->contents[i]->transport().attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++		{
++			qDebug() << d->contents[i]->name() << "    RAW-UDP";
++			startRawUdpConnection(d->contents[i]);
++		}
++	}
++}
++
++JingleContent *JingleSession::contentWithName(const QString& n)
++{
++	qDebug() << "There are" << d->contents.count() << "contents";
++	for (int i = 0; i < d->contents.count(); i++)
++	{
++		if (d->contents.at(i)->name() == n)
++			return d->contents[i];
++	}
++	return 0;
++}
++
++void JingleSession::setTo(const Jid& to)
++{
++	d->to = to;
++}
++
++void JingleSession::sendIceUdpCandidates()
++{
++	qDebug() << "Sending ice-udp candidates (Not Implemented Yet)";
++	/*JT_JingleAction *cAction = new JT_JingleAction(d->rootTask);
++	cAction->setSession(this);
++	QDomDocument doc("");
++	QDomElement candidate = doc.createElement("candidate");
++	candidate.setAttribute("foo", "bar");
++	//cAction->sendCandidate(candidate);
++	// --> Or better : sendTransportInfo(QDomElement transport);*/
++}
++
++void JingleSession::startRawUdpConnection(JingleContent *c)
++{
++	QDomElement e = c->transport();
++	qDebug() << "Start raw-udp connection (still 'TODO') for content" << c->name();
++	
++	connect(c, SIGNAL(needData(XMPP::JingleContent*)), this, SIGNAL(needData(XMPP::JingleContent*)));
++	//FIXME:This signal should not go trough JingleSession and be used directly with the JingleContent by the application.
++	c->startSending();
++
++	//Sending my own candidate:
++	JT_JingleAction *cAction = new JT_JingleAction(d->rootTask);
++	d->actions << cAction;
++	connect(cAction, SIGNAL(finished()), this, SLOT(slotAcked()));
++	cAction->setSession(this);
++	cAction->transportInfo(c);
++	cAction->go(true);
++}
++
++void JingleSession::slotSessTerminated()
++{
++	qDebug() << "JingleSession::slotSessTerminated() called !";
++	if (sender())
++		deleteAction(static_cast<JT_JingleAction*>(sender()));
++	qDebug() << "Emit terminated() signal";
++	emit terminated();
++}
++
++void JingleSession::addSessionInfo(const QDomElement& e)
++{
++	QString info = e.tagName();
++	if (info == "trying")
++	{
++		d->responderTrying = true;
++	}
++	else if (info == "received")
++	{
++		//FIXME:For what Content do we receive that info ?
++		//How do I know all content's connections are established, in both directions ?
++		//What if it isn't the case ?
++
++		// We consider every ports are opened, no firewall (that's the specification that tells us that.)
++		for (int i = 0; i < contents().count(); i++)
++		{
++			//We tell the content that it is able to send data.
++			contents()[i]->setSending(true);
++		}
++	}
++}
++
++void JingleSession::addTransportInfo(const QDomElement& e)
++{
++	// this should really depend on the transport used...
++	qDebug() << "Transport info for content named" << e.attribute("name");
++	
++	JingleContent *content = contentWithName(e.attribute("name"));
++	
++	qDebug() << "Found content with address" << (int*) content;
++	
++	connect(content, SIGNAL(needData(XMPP::JingleContent*)), this, SIGNAL(needData(XMPP::JingleContent*)));
++	content->addTransportInfo(e);
++	
++	//If it is a candidate, we try to connect.
++	//FIXME:is a transport-info always a candidate ? --> Currently, we consider this can only a candidate.
++	//TODO:There should be a JingleTransport Class as the transport will be used everywhere
++	//	Also, we could manipulate the QDomElement
++	QDomElement candidate = e.firstChildElement().firstChildElement(); //This is the candidate.
++}
++
++JingleSession::State JingleSession::state() const
++{
++	return d->state;
++}
++
++void JingleSession::slotReceivingData()
++{
++	// Whatever the sender content is, we send the same received informational message.
++	// That's from the raw-udp specification, later, we will have to do fifferent things
++	// here depending on the transport method used in the sender content.
++	
++	JT_JingleAction *rAction = new JT_JingleAction(d->rootTask);
++	d->actions << rAction;
++	connect(rAction, SIGNAL(finished()), this, SLOT(slotAcked()));
++	rAction->setSession(this);
++	rAction->received();
++	rAction->go(true);
++}
++
++
++
++//--------------------------
++// JingleReason
++//--------------------------
++
++
++class JingleReason::Private
++{
++public:
++	QString reasonText;
++	Type type;
++};
++
++JingleReason::JingleReason()
++: d(new Private)
++{
++	d->reasonText = "";
++	d->type = NoReason;
++}
++
++JingleReason::JingleReason(JingleReason::Type type, const QString& text)
++: d(new Private)
++{
++	d->reasonText = text;
++	d->type = type;
++}
++
++JingleReason::~JingleReason()
++{
++
++}
++
++void JingleReason::setText(const QString& r)
++{
++	d->reasonText = r;
++}
++
++void JingleReason::setType(JingleReason::Type t)
++{
++	d->type = t;
++}
++
++QString JingleReason::text() const
++{
++	return d->reasonText;
++}
++
++JingleReason::Type JingleReason::type() const
++{
++	return d->type;
++}
++
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglesession.h iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesession.h
+--- iris-1.0.0/src/xmpp/jingle/jinglesession.h	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesession.h	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,343 @@
++/*
++ * jinglesession.cpp - Jingle session
++ * 
++ * This class defines a Jingle Session which contains all information about the session.
++ * This is here that the state machine is and where almost everything is done for a session.
++ * 
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++#ifndef JINGLE_SESSION
++#define JINGLE_SESSION
++
++#include <QObject>
++#include <QString>
++#include <QDomElement>
++
++#define NS_JINGLE "urn:xmpp:tmp:jingle:0"
++#define NS_JINGLE_TRANSPORTS_RAW "urn:xmpp:tmp:jingle:transports:raw-udp:0"
++#define NS_JINGLE_TRANSPORTS_ICE "urn:xmpp:tmp:jingle:transports:ice-udp:0"
++#define NS_JINGLE_APPS_RTP "urn:xmpp:tmp:jingle:apps:rtp:0"
++
++#define IRIS_EXPORT
++
++#include "im.h"
++//#include "xmpp_client.h"
++//#include "xmpp_jid.h"
++#include "jingletasks.h"
++
++namespace XMPP
++{
++	/*
++	 * This class defines a jingle reason used when sending
++	 * a session-terminate jingle action.
++	 */
++	class IRIS_EXPORT JingleReason
++	{
++	public:
++		/*
++		 * Default constructor : create a No Reason reason with no text.
++		 */
++		JingleReason();
++		enum Type {
++			Decline = 0,
++			Busy,
++			UnsupportedApplications,
++			NoReason
++		};
++		/*
++		 * Creates a reason with a type and a text reason.
++		 */
++		JingleReason(JingleReason::Type, const QString& text = QString());
++		~JingleReason();
++		
++		//static Type stringToType(const QString&);
++
++		void setType(Type);
++		void setText(const QString&);
++		Type type() const;
++		QString text() const;
++	private:
++		class Private;
++		Private *d;
++	};
++
++	class JingleContent;
++	class JT_JingleAction;
++	class JT_PushJingleSession;
++
++	class IRIS_EXPORT JingleSession : public QObject
++	{
++		Q_OBJECT
++	public:
++		JingleSession();
++		JingleSession(Task*, const Jid&);
++		~JingleSession();
++
++		/*
++		 * Adds a content to the session.
++		 * Currently, the content is just added in the contents list.
++		 * TODO: addContent should add a content even when the session
++		 * is in ACTIVE state so the session is modified with a content-add action.
++		 */
++		void addContent(JingleContent*);
++
++		/*
++		 * Same as above but the content is in a QDomElement form.
++		 * For convenience.
++		 */
++		void addContent(const QDomElement&);
++
++		/*
++		 * Adds multiple contents to the session. It is advised
++		 * to use this method instead of addContent() even for
++		 * one content.
++		 */
++		void addContents(const QList<JingleContent*>&);
++
++		/* 
++		 * Adds session information to the session
++		 * (used to inform the session that a "received"
++		 * informational message has been received for eg.)
++		 * Argument is a QDomElement containing the child(s -- TODO)
++		 * of the jingle tag in a jingle stanza.
++		 */
++		void addSessionInfo(const QDomElement&);
++
++		/*
++		 * Adds transport info to the session.
++		 * Mostly, it adds a candidate to the session
++		 * and the session starts to try to connect to it.
++		 * Argument is a QDomElement containing the child(s -- TODO)
++		 * of the jingle tag in a jingle stanza.
++		 */
++		void addTransportInfo(const QDomElement&);
++
++		/*
++		 * Sends a content-accept jingle action.
++		 * Not used yet, may be removed.
++		 */
++		void acceptContent();
++
++		/*
++		 * Sends a session-accept jingle action.
++		 * Not used yet, may be removed.
++		 */
++		void acceptSession();
++
++		/*
++		 * Sends a remove-content jingle action with the content
++		 * name given as an argument.
++		 */
++		void removeContent(const QString&);
++
++		/*
++		 * Sends a remove-content jingle action with the contents
++		 * name given as an argument.
++		 * Prefer this method instead of removeContent(const QString&);
++		 */
++		void removeContent(const QStringList&);
++
++		/*
++		 * Sends a session-terminate jingle action with the reason r.
++		 * Once the responder sends the acknowledgement stanza, the
++		 * signal terminated() is emitted.
++		 */
++		void sessionTerminate(const JingleReason& r = JingleReason());
++
++		/*
++		 * Sends a ringing informational message.
++		 * FIXME:Would be better to use the sessionInfo() method.
++		 */
++		void ring();
++		
++		/*
++		 * Returns the Jid of the other peer with whom the session is established.
++		 */
++		Jid to() const;
++
++		/*
++		 * Returns the contents of this session.
++		 * In Pending state, it should return contents sent by the other peer.
++		 * In Active state, it should return contents being used.
++		 * This is right as we know which contents we do support.
++		 */
++		QList<JingleContent*> contents() const;
++
++		/*
++		 * Starts the session by sending a session-initiate jingle action.
++		 * if a SID has been set, it will be overwritten by a new generated one.
++		 */
++		void start();
++		
++		/* This method sets the SID.
++		 * For an incoming session, the sid must be set and not
++		 * generated randomly.
++		 * Calling the start method after this one will change the SID
++		 */
++		void setSid(const QString&);
++
++		/*
++		 * Sets peer's Jid.
++		 */
++		void setTo(const Jid&);
++
++		/*
++		 * Sets the initiator Jid.
++		 * This can be already set if a session is redirected.
++		 * Session redirection is NOT supported yet.
++		 */
++		void setInitiator(const QString&); //Or const Jid& ??
++
++		/*
++		 * Return initiator Jid.
++		 */
++		QString initiator() const;
++		
++		/*
++		 * Start negotiation.
++		 * This function is called after receiving a session initiate.
++		 * This will start negotiating a connection depending on the transport.
++		 */
++		void startNegotiation();
++		
++		/*
++		 * Returns a pointer to the first JingleContent with the name n.
++		 * Each content must have a unique name so returning the first
++		 * one returns the only one.
++		 */
++		JingleContent *contentWithName(const QString& n);
++		
++		/*
++		 * Returns the sid of this session.
++		 */
++		QString sid() const;
++
++		/*
++		 * Call this function when a session-accept jingle action has been received for it.
++		 * Once the session is accepted, we will get the supported payloads of the initiator
++		 * and switch to Active state, Media can begin to flow on each content's socket.
++		 */
++		void sessionAccepted(const QDomElement&);
++
++		// Jingle actions
++		enum JingleAction {
++			SessionInitiate = 0,
++			SessionTerminate,
++			SessionAccept,
++			SessionInfo,
++			ContentAdd,
++			ContentRemove,
++			ContentModify,
++			TransportReplace,
++			TransportAccept,
++			TransportInfo,
++			NoAction
++		};
++		
++		// Session states
++		enum State {
++			Pending = 0,
++			Active,
++			Ended
++		};
++		
++		/*
++		 * Returns the current state of the session.
++		 */
++		State state() const;
++
++	signals:
++		
++		/*
++		 * Emitted once a session-terminate has been acknowledged
++		 */
++		void terminated();
++		
++		/* 
++		 * needData() is emitted once for each content.
++		 * Once it has been emitted, streaming must start on this socket until stopSending is emitted.
++		 * FIXME: Shouldn't pass by here, should stay in JingleContent.
++		 */
++		void needData(XMPP::JingleContent*);
++
++		/**
++		 * Emitted when the session state has changed (Pending --> Active)
++		 */
++		void stateChanged();
++	public slots:
++		
++		/*
++		 * This slot is called when a content-remove has been acked.
++		 */
++		void slotRemoveAcked();
++		
++		/*
++		 * This slot is called when a session-terminate has been acked.
++		 */
++		void slotSessTerminated();
++
++		/*
++		 * This slot is called when data is received on the raw udp socket.
++		 */
++		void slotRawUdpDataReady();
++
++		/*
++		 * Called when a content has been established.
++		 */
++		void slotContentConnected();
++
++		/*
++		 * This slot is called when a JT_JingleAction has been acknowledged
++		 * and we just have to delete it.
++		 */
++		void slotAcked();
++
++		/*
++		 * This slot is called when the session has been accepted by the responder.
++		 */
++		void slotSessionAcceptAcked();
++
++		/*
++		 * This slot is called when a "receive" informational message has been received.
++		 * Currently, this slot simply calls setSending() on all contents.
++		 */
++		void slotReceivingData();
++
++	private:
++		class Private;
++		Private *d;
++		
++		/*
++		 * Sends ice udp cadidates
++		 */
++		void sendIceUdpCandidates();
++		
++		/*
++		 * Starts a raw udp connection for this JingleContent.
++		 * (Create socket, ask to start sending data on it)
++		 */
++		void startRawUdpConnection(JingleContent*);
++		
++		/*
++		 * Deletes an action when it is not used anymore.
++		 */
++		void deleteAction(JT_JingleAction*);
++	};
++}
++
++#endif
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglesessionmanager.cpp iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesessionmanager.cpp
+--- iris-1.0.0/src/xmpp/jingle/jinglesessionmanager.cpp	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesessionmanager.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,389 @@
++/*
++ * jinglesessionmanager.cpp - Manager for Jingle sessions
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#include "jinglesessionmanager.h"
++#include "jingletasks.h"
++
++#include <QHttp>
++
++using namespace XMPP;
++
++class JingleSessionManager::Private
++{
++public:
++	JT_PushJingleAction *pjs;
++	Client *client;
++	QList<JingleSession*> sessions;
++	QStringList supportedTransports;
++	QList<QDomElement> supportedAudioPayloads;
++	QList<QDomElement> supportedVideoPayloads;
++	QStringList supportedProfiles;
++	QList<int> usedPorts;
++	int firstPort;
++	QString ip;
++	QHttp *http;
++};
++
++JingleSessionManager::JingleSessionManager(Client* c)
++: d(new Private)
++{
++	qDebug() << "JingleSessionManager::JingleSessionManager created.";
++	d->client = c;
++	d->pjs = new JT_PushJingleAction(d->client->rootTask());
++	connect(d->pjs, SIGNAL(newSessionIncoming()),
++		this, SLOT(slotSessionIncoming()));
++	connect(d->pjs, SIGNAL(removeContent(const QString&, const QStringList&)),
++		this, SLOT(slotRemoveContent(const QString&, const QStringList&)));
++	connect(d->pjs, SIGNAL(sessionInfo(const QDomElement&)),
++		this, SLOT(slotSessionInfo(const QDomElement&)));
++	connect(d->pjs, SIGNAL(transportInfo(const QDomElement&)),
++		this, SLOT(slotTransportInfo(const QDomElement&)));
++	connect(d->pjs, SIGNAL(sessionTerminate(const QString&, const JingleReason&)),
++		this, SLOT(slotSessionTerminate(const QString&, const JingleReason&)));
++	connect(d->pjs, SIGNAL(sessionAccepted(const QDomElement&)),
++		this, SLOT(slotSessionAccepted(const QDomElement&)));
++
++	Features f = d->client->features();
++	
++	f.addFeature(NS_JINGLE);
++//	f.addFeature(NS_JINGLE_TRANSPORTS_ICE);
++	f.addFeature(NS_JINGLE_TRANSPORTS_RAW);
++	f.addFeature(NS_JINGLE_APPS_RTP);
++//	f.addFeature("urn:xmpp:tmp:jingle:apps:video-rtp");
++
++	d->client->setFeatures(f);
++
++	d->firstPort = 9000;
++	
++	//Get External IP address, This is not Standard and might not work but let's try it before we have ICE support
++	//whatismyip.org has a better interface for this
++	//d->http = new QHttp(this);
++	//d->http->setHost("www.swlink.net");
++	//connect(d->http, SIGNAL(done(bool)), this, SLOT(slotExternalIPDone(bool)));
++	//d->http->get("/~styma/REMOTE_ADDR.shtml");
++}
++
++void JingleSessionManager::slotExternalIPDone(bool err)
++{
++	d->ip = "";
++	if (err)
++	{
++		qDebug() << "err =" << err;
++		d->http->deleteLater(); //FIXME:Not Sure about that
++		return;
++	}
++		
++	QByteArray pageData = d->http->readAll();
++	d->ip = pageData.split('\n').at(4);
++	qDebug() << "Received External IP :" << d->ip;
++
++	QDomDocument *xmlPage = new QDomDocument();
++	QString errMess;
++	int line, col;
++	if (xmlPage->setContent(pageData, false, &errMess, &line, &col))
++	{
++		qDebug() << "Parsing Ok";
++		/*d->ip= "";*/
++	}
++	else
++	{
++		qDebug() << " JingleSessionManager::slotExternalIPDone : Unable to parse HTML document." << errMess << line << col;
++	}
++	
++	delete d->http;
++}
++
++void JingleSessionManager::setExternalIP(const QString& eip)
++{
++	d->ip = eip;
++}
++
++QString JingleSessionManager::externalIP() const
++{
++	return d->ip;
++}
++
++JingleSessionManager::~JingleSessionManager()
++{
++	delete d;
++}
++
++void JingleSessionManager::setSupportedTransports(const QStringList& transports)
++{
++	d->supportedTransports = transports;
++}
++
++void JingleSessionManager::setSupportedAudioPayloads(const QList<QDomElement>& payloads)
++{
++	d->supportedAudioPayloads = payloads;
++}
++
++QList<QDomElement> JingleSessionManager::supportedAudioPayloads() const
++{
++	return d->supportedAudioPayloads;
++}
++
++void JingleSessionManager::setSupportedVideoPayloads(const QList<QDomElement>& payloads)
++{
++	d->supportedVideoPayloads = payloads;
++}
++
++QList<QDomElement> JingleSessionManager::supportedVideoPayloads() const
++{
++	return d->supportedVideoPayloads;
++}
++
++void JingleSessionManager::setSupportedProfiles(const QStringList& profiles)
++{
++	d->supportedProfiles = profiles;
++}
++
++JingleSession *JingleSessionManager::startNewSession(const Jid& toJid, const QList<JingleContent*>& contents)
++{
++	XMPP::JingleSession *session = new XMPP::JingleSession(d->client->rootTask(), toJid.full());
++	session->setInitiator(d->client->jid().full());
++	session->addContents(contents);
++	d->sessions << session;
++	connect(session, SIGNAL(terminated()), this, SLOT(slotSessionTerminated()));
++	//connect(others);
++	session->start();
++	return session;
++}
++
++void JingleSessionManager::slotSessionTerminated()
++{
++	JingleSession* sess = static_cast<JingleSession*>(sender());
++
++	for (int i = 0; i < d->sessions.count(); i++)
++	{
++		if (d->sessions[i] == sess)
++			d->sessions.removeAt(i);
++	}
++}
++
++void JingleSessionManager::slotSessionIncoming()
++{
++	qDebug() << "JingleSessionManager::slotSessionIncoming() called.";
++	
++	JingleSession *sess = d->pjs->takeNextIncomingSession();
++	d->sessions << sess;
++	connect(sess, SIGNAL(terminated()), this, SLOT(slotSessionTerminated()));
++	//QList<QString> incompatibleContents;
++	
++	QList<QString> unsupportedPayloads;
++	// This is a list of the names of the contents which have no supported payloads.
++	
++	QList<QString> unsupportedTransports;
++	// This is a list of the names of the contents which have no supported transports
++	// We have to remove all contents present in those lists.
++	//
++	// If no content is supported, reject the session because it's not possible to establish a session.
++
++	for (int i = 0; i < sess->contents().count(); i++)
++	{
++		JingleContent *c = sess->contents()[i];
++		
++		//Set supported payloads for this content.
++		c->setPayloadTypes(c->type() == JingleContent::Audio ? d->supportedAudioPayloads : d->supportedVideoPayloads);
++
++		// Check payloads for the content c
++		if (!checkSupportedPayloads(c))
++		{
++			//incompatibleContents << c->name();
++			unsupportedPayloads << c->name();
++			continue;
++		}
++		
++		if (!checkSupportedTransport(c))
++		{
++			//incompatibleContents << c->name();
++			unsupportedTransports << c->name();
++		}
++	}
++	
++	if (unsupportedPayloads.count() + unsupportedTransports.count() == sess->contents().count())
++	{
++		//Reject the session.
++		JingleReason r(JingleReason::UnsupportedApplications);
++		sess->sessionTerminate(r);
++		//What happens when we receive the ack of the session-terminate ?
++		return;
++	}
++	else if (unsupportedPayloads.count() + unsupportedTransports.count() > 0)
++	{
++		//remove this contents list
++		sess->removeContent(unsupportedPayloads + unsupportedTransports);
++		return;
++	}
++	
++	emit newJingleSession(sess);
++	
++	d->sessions.last()->ring();
++	
++	d->sessions.last()->startNegotiation();
++}
++
++bool JingleSessionManager::checkSupportedPayloads(JingleContent *c)
++{
++	qDebug() << "We have" << c->responderPayloads().count() << "responder payloads in this content.";
++	for (int i = 0; i < c->payloadTypes().count(); i++)
++	{
++		qDebug() << "We have" << d->supportedAudioPayloads.count() << "supported payloads.";
++		for (int j = 0; j < d->supportedAudioPayloads.count(); j++)
++		{
++			qDebug() << "compare" << c->payloadTypes().at(i).attribute("name") << "to" << d->supportedAudioPayloads.at(j).attribute("name");
++			if (c->payloadTypes().at(i).attribute("name") == d->supportedAudioPayloads.at(j).attribute("name"))
++			{
++				//This payload name is supported.
++				//A static method should be written to compare 2 payloads elements.
++				qDebug() << "return true";
++				return true;
++			}
++		}
++	}
++
++	qDebug() << "return false";
++	return false;
++}
++
++bool JingleSessionManager::checkSupportedTransport(JingleContent *c)
++{
++	/*for (int i = 0; i < d->supportedTransports.count(); i++)
++	{
++		qDebug() << "compare" << c->transport().attribute("xmlns") << "to" << d->supportedTransports.at(i);
++		if (c->transport().attribute("xmlns") == d->supportedTransports.at(i))
++		{
++			qDebug() << "return true";
++			return true;
++		}
++	}
++	qDebug() << "return false";*/
++
++	return true;
++}
++
++//void JingleSessionManager::removeContent(const QString& sid, const QString& cName)
++//{
++//	for (int i = 0; i < )
++//}
++
++void JingleSessionManager::slotRemoveContent(const QString& sid, const QStringList& cNames)
++{
++	qDebug() << "JingleSessionManager::slotRemoveContent(" << sid << ", " << cNames << ") called.";
++	//emit contentRemove(sid, cNames); //The slotRemoveContent slot should not exist so we can connect both signals directly.
++	/*
++	 * Whatever we have to do at this point will be done by the application on the JingleSession.
++	 * That means that the application must keep a list of the JingleSession or this class should
++	 * give access to the session list.
++	 */
++}
++
++JingleSession *JingleSessionManager::session(const QString& sid)
++{
++	JingleSession *sess;
++	sess = 0;
++	for (int i = 0; i < d->sessions.count(); i++)
++	{
++		if (d->sessions.at(i)->sid() == sid)
++		{
++			sess = d->sessions.at(i);
++			break;
++		}
++	}
++	return sess;
++}
++
++void JingleSessionManager::slotSessionInfo(const QDomElement& x)
++{
++	JingleSession *sess = session(x.attribute("sid"));
++	if (sess == 0)
++	{
++		//unknownSession();
++		return;
++	}
++	sess->addSessionInfo(x.firstChildElement());
++}
++
++void JingleSessionManager::slotTransportInfo(const QDomElement& x)
++{
++	JingleSession *sess = session(x.attribute("sid"));
++	if (sess == 0)
++	{
++		qDebug() << "Session is null, We have a proble here...";
++		//unknownSession();
++		return;
++	}
++	//sess->contentWithName(x.firstChildElement().attribute("name"))->addTransportInfo(x.firstChildElement().firstChildElement());
++	sess->addTransportInfo(x.firstChildElement());
++}
++
++void JingleSessionManager::slotSessionTerminate(const QString& sid, const JingleReason& reason)
++{
++	Q_UNUSED(reason)
++	JingleSession *sess = session(sid);
++	if (!sess)
++	{
++		//sendUnknownSession([need the stanza id]);
++		return;
++	}
++
++	//Remove the session from the sessions list (the session is not destroyed, it has to be done by the application.)
++	for (int i = 0; i < d->sessions.count(); i++)
++	{
++		if (sess == d->sessions[i])
++		{
++			d->sessions.removeAt(i);
++			break;
++		}
++	}
++	emit sessionTerminate(sess);
++	
++}
++
++int JingleSessionManager::nextRawUdpPort()
++{
++	int lastUsed;
++	if (d->usedPorts.count() == 0)
++		lastUsed = d->firstPort - 1;
++	else
++		lastUsed = d->usedPorts.last();
++	d->usedPorts << lastUsed + 1 << lastUsed + 2;
++	qDebug() << "JingleSessionManager::nextRawUdpPort() returns" << (lastUsed + 1);
++	return (lastUsed + 1);
++}
++
++void JingleSessionManager::setFirstPort(int f)
++{
++	d->firstPort = f;
++}
++
++void JingleSessionManager::slotSessionAccepted(const QDomElement& x)
++{
++	JingleSession *sess = session(x.attribute("sid"));
++	if (sess == 0)
++	{
++		qDebug() << "Session is null, We have a proble here...";
++		//unknownSession();
++		return;
++	}
++	
++	qDebug() << "JingleSessionManager::slotSessionAccept(const QDomElement& x) : call sess->sessionAccepted(x);";
++	sess->sessionAccepted(x);
++}
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglesessionmanager.h iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesessionmanager.h
+--- iris-1.0.0/src/xmpp/jingle/jinglesessionmanager.h	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesessionmanager.h	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,158 @@
++/*
++ * jinglesessionmanager.cpp - Manager for Jingle sessions
++ *
++ * Manages all Jingle sessions.
++ * This class receives all incoming jingle actions and perform these
++ * actions on the right jingle session.
++ * It also keeps information about protocols supported by the application (transports, payloads, profiles)
++ *
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++#ifndef JINGLE_SESSION_MANAGER
++#define JINGLE_SESSION_MANAGER
++
++//#include <QObject>
++
++#include "im.h"
++//#include "xmpp_client.h"
++//#include "xmpp_jid.h"
++
++namespace XMPP
++{
++	class JingleSession;
++	class JingleContent;
++	class JingleReason;
++	class JingleSessionManager : public QObject
++	{
++		Q_OBJECT
++	public:
++		JingleSessionManager(Client*);
++		~JingleSessionManager();
++		
++		/*
++		 * Create a new jingle session to a Jid and with a list of contents,
++		 * starts it and returns it.
++		 */
++		XMPP::JingleSession *startNewSession(const Jid&, const QList<JingleContent*>&);
++		
++		/*
++		 * Set supported transports for jingle sessions.
++		 */
++		void setSupportedTransports(const QStringList&);
++		
++		/*
++		 * Set supported audio payloads for jingle sessions.
++		 */
++		void setSupportedAudioPayloads(const QList<QDomElement>&);
++
++		/*
++		 * Returns the supported audio payloads.
++		 */
++		QList<QDomElement> supportedAudioPayloads() const;
++		
++		/*
++		 * Set supported video payloads for jingle sessions.
++		 */
++		void setSupportedVideoPayloads(const QList<QDomElement>&); // FIXME:a class name QNodeList does exists in Qt.
++
++		/*
++		 * Returns the supported video payloads.
++		 */
++		QList<QDomElement> supportedVideoPayloads() const;
++		
++		/*
++		 * Set supported profiles for jingle sessions.
++		 */
++		void setSupportedProfiles(const QStringList&);
++
++		/*
++		 * Provides the next usable port for a raw-udp session.
++		 * As the application should create a rtcp port with the
++		 * provided rtp socket port + 1, this method will always
++		 * give a port incremented by 2.
++		 * The first port will be 9000 by default but it can be modified
++		 * with setFirstPort().
++		 * Also, this method will share a list of used ports with the
++		 * iceUdpPort method.
++		 * It would be nice to be informed of the ports which are freed
++		 * when a session is terminated so we can reuse them.
++		 */
++		int nextRawUdpPort();
++		void setFirstPort(int);
++
++		QString externalIP() const;
++		void setExternalIP(const QString& eip);
++	signals:
++		
++		/*
++		 * Emitted when a new jingle session comes.
++		 */
++		void newJingleSession(XMPP::JingleSession*);
++
++		/*
++		 * Emitted when a session-terminate is received.
++		 */
++		void sessionTerminate(XMPP::JingleSession*);
++	
++	public slots:
++		/* 
++		 * Slots for each jingle action
++		 */
++		void slotSessionIncoming();
++		void slotRemoveContent(const QString&, const QStringList&);
++		void slotSessionInfo(const QDomElement&);
++		void slotTransportInfo(const QDomElement&);
++		void slotSessionTerminate(const QString&, const JingleReason&);
++		void slotSessionAccepted(const QDomElement&);
++
++		/*
++		 * This slot is called when a session has been
++		 * terminated and should be removed from the
++		 * sessions list.
++		 */
++		void slotSessionTerminated();
++
++		/*
++		 * This slot is called when the external IP has been retrieved by http
++		 */
++		void slotExternalIPDone(bool);
++
++	private:
++		class Private;
++		Private *d;
++		/*
++		 * Returns the session with the SID sid.
++		 */
++		JingleSession *session(const QString& sid);
++
++		/*
++		 * Check if this content has supported contents.
++		 * If yes, returns true, returns false if not.
++		 */
++		bool checkSupportedPayloads(JingleContent *c);
++		
++		/*
++		 * Check if this content has a supported transport.
++		 * If yes, returns true, returns false if not.
++		 */
++		bool checkSupportedTransport(JingleContent *c);
++
++	};
++}
++
++#endif
+diff -Nur iris-1.0.0/src/xmpp/jingle/jingletasks.cpp iris-1.0.0-023_jingle/src/xmpp/jingle/jingletasks.cpp
+--- iris-1.0.0/src/xmpp/jingle/jingletasks.cpp	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jingletasks.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,687 @@
++/*
++ * jingletasks.cpp - Tasks for the Jingle specification.
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#include <QtDebug>
++#include <QNetworkInterface>
++#include <QUdpSocket>
++#include <stdio.h>
++
++#include "jinglesessionmanager.h"
++
++#include "jingletasks.h"
++#include "protocol.h"
++#include "xmpp_xmlcommon.h"
++
++using namespace XMPP;
++
++JingleSession::JingleAction jingleAction(const QDomElement& x)
++{
++	QString action = x.firstChildElement().attribute("action");
++	if (action == "session-initiate")
++		return JingleSession::SessionInitiate;
++	else if (action == "session-terminate")
++		return JingleSession::SessionTerminate;
++	else if (action == "session-accept")
++		return JingleSession::SessionAccept;
++	else if (action == "session-info")
++		return JingleSession::SessionInfo;
++	else if (action == "content-add")
++		return JingleSession::ContentAdd;
++	else if (action == "content-remove")
++		return JingleSession::ContentRemove;
++	else if (action == "content-modify")
++		return JingleSession::ContentModify;
++	else if (action == "transport-replace")
++		return JingleSession::TransportReplace;
++	else if (action == "transport-accept")
++		return JingleSession::TransportAccept;
++	else if (action == "transport-info")
++		return JingleSession::TransportInfo;
++	else
++		return JingleSession::NoAction;
++}
++
++
++
++//------------------------
++// JT_PushJingleAction
++//------------------------
++//RECEIVES THE ACTIONS
++
++static JingleReason::Type stringToType(const QString& str)
++{
++	if (str == "busy")
++	{
++		return JingleReason::Busy;
++	}
++	else if (str == "decline")
++	{
++		return JingleReason::Decline;
++	}
++	else
++	{
++		return JingleReason::NoReason;
++	}
++
++}
++
++class JT_PushJingleAction::Private
++{
++public:
++	JingleSession *incomingSession;
++	QList<JingleSession*> incomingSessions;
++	QDomElement iq;
++	QString id;
++	Jid from;
++};
++
++JT_PushJingleAction::JT_PushJingleAction(Task *parent)
++: Task(parent), d(new Private)
++{
++	qDebug() << "Creating the PushJingleSession task....";
++}
++
++JT_PushJingleAction::~JT_PushJingleAction()
++{
++	qDebug() << "Deleting the PushJingleSession task....";
++	delete d;
++}
++
++void JT_PushJingleAction::onGo()
++{
++//	send(d->iq);
++}
++
++bool JT_PushJingleAction::take(const QDomElement &x)
++{
++	/*
++	 * We take this stanza when it is a session-initiate stanza for sure.
++	 * Now, 2 possibilities :
++	 * 	* This task is used by the JingleSession to established the connection
++	 * 	* A new JT_JingleSession is used by the JingleSession to established the connection
++	 * I'd rather use the second one, see later...
++	 */
++	if (x.firstChildElement().tagName() != "jingle")
++		return false;
++	
++	if (x.attribute("type") == "error")
++	{
++		jingleError(x);
++		return true;
++	}
++
++	QStringList cName;
++	QString sid = x.firstChildElement().attribute("sid");
++	d->from = Jid(x.attribute("from"));
++	QDomElement jingle;
++	QDomElement content;
++	QDomElement reason, e;
++	QString condition;
++	QString text;
++	switch(jingleAction(x))
++	{
++	case JingleSession::SessionInitiate :
++		qDebug() << "New Incoming session : " << sid;
++		d->id = x.attribute("id");
++		ack();
++
++		//Prepare the JingleSession instance.
++		d->incomingSession = new JingleSession(parent(), Jid());
++		d->incomingSession->setTo(x.attribute("from"));
++		jingle = x.firstChildElement();
++		d->incomingSession->setInitiator(jingle.attribute("initiator"));
++		d->incomingSession->setSid(jingle.attribute("sid"));
++		content = jingle.firstChildElement();
++		while (!content.isNull())
++		{
++			if (content.tagName() == "content")
++				d->incomingSession->addContent(content);
++			content = content.nextSiblingElement();
++		}
++
++		d->incomingSessions << d->incomingSession;
++
++		emit newSessionIncoming();
++		 /* TODO : 
++		  * 	Continue to negotiate the contents to use --> Done by the JingleSession.
++		  */
++		break;
++	case JingleSession::ContentRemove : 
++		qDebug() << "Content remove for session " << sid;
++		// Ack content-remove
++		d->id = x.attribute("id");
++		ack();
++		
++		content = x.firstChildElement().firstChildElement();
++		while (!content.isNull())
++		{
++			cName << content.attribute("name");
++			qDebug() << " * Remove : " << cName;
++			content = content.nextSiblingElement();
++		}
++		emit removeContent(sid, cName);
++		/*if (d->state == WaitContentAccept)
++		{
++			d->state = StartNegotiation;
++			 *
++			 * Content has been removed, we can take it as a content-accept.
++			 * Now, we stop ringing but the session should change it by itself depending
++			 * on the state when receiving a content-remove
++			 * After we acknowledge the responder that the content has been removed,
++			 * we must start negotiate a candidate with him (depending if we use ICE-UDP or RAW-UDP)
++			 * ADVICE: Begin with RAW-UDP, it is simpler.
++			 *
++		}*/
++		break;
++	case JingleSession::SessionInfo :
++		qDebug() << "Session Info for session " << sid;
++		// Ack session-info
++		d->id = x.attribute("id");
++		ack();
++		
++		emit sessionInfo(x.firstChildElement());
++		break;
++	case JingleSession::TransportInfo :
++		qDebug() << "Transport Info for session " << sid;
++		d->id = x.attribute("id");
++		ack();
++		
++		emit transportInfo(x.firstChildElement());
++
++		break;
++	case JingleSession::SessionTerminate :
++		qDebug() << "Transport Info for session " << sid;
++		d->id = x.attribute("id");
++		ack();
++		
++		reason = x.firstChildElement().firstChildElement();
++		e = reason.firstChildElement();
++		while(!e.isNull())
++		{
++			if (e.tagName() == "condition")
++				condition = e.firstChildElement().tagName();
++			else if (e.tagName() == "text")
++				text = e.firstChildElement().toText().data();
++
++			e = e.nextSiblingElement();
++		}
++		
++		emit sessionTerminate(sid, JingleReason(stringToType(condition), text));
++
++		break;
++	case JingleSession::SessionAccept :
++		qDebug() << "Transport Info for session " << sid;
++		d->id = x.attribute("id");
++		ack();
++
++		emit sessionAccepted(x.firstChildElement());
++		break;
++	default:
++		qDebug() << "There are some troubles with the Jingle Implementation. Be carefull that this is still low performances software.";
++	}
++	return true;
++}
++
++JingleSession *JT_PushJingleAction::takeNextIncomingSession()
++{
++	return d->incomingSessions.takeLast();
++}
++
++void JT_PushJingleAction::ack()
++{
++	d->iq = createIQ(doc(), "result", d->from.full(), d->id);
++	send(d->iq);
++}
++
++void JT_PushJingleAction::jingleError(const QDomElement& x)
++{
++	qDebug() << "There was an error from the responder. Not supported yet.";
++	Q_UNUSED(x)
++	//emit error(???);
++}
++
++//-----------------------
++// JT_JingleAction
++//-----------------------
++
++class JT_JingleAction::Private
++{
++public :
++	JingleSession *session;
++	QDomElement iq;
++	QString sid;
++	Jid to;
++};
++
++JT_JingleAction::JT_JingleAction(Task *parent)
++: Task(parent), d(new Private())
++{
++	qDebug() << "Creating JT_JingleAction";
++	d->session = 0;
++}
++
++JT_JingleAction::~JT_JingleAction()
++{
++	delete d;
++}
++
++void JT_JingleAction::setSession(JingleSession *sess)
++{
++	d->session = sess;
++}
++
++bool interfaceOrder(const QHostAddress& a1, const QHostAddress& a2)
++{
++	Q_UNUSED(a2)
++	if ((a1 != QHostAddress::LocalHost) && (a1 != QHostAddress::Null) && (a1.protocol() != QAbstractSocket::IPv6Protocol))
++		return true;
++	return false;
++}
++
++void JT_JingleAction::initiate()
++{
++	qDebug() << id();
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-initiate");
++	jingle.setAttribute("initiator", client()->jid().full());
++	jingle.setAttribute("sid", d->session->sid());
++
++	QString eip = client()->jingleSessionManager()->externalIP();
++
++	for (int i = 0; i < d->session->contents().count(); i++)
++	{
++		QDomElement transport = d->session->contents()[i]->transport();
++		//qDebug() << "Transport from the JingleContent is : " << client()->stream().xmlToString(transport, false);
++		if (transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++		{
++			qDebug() << "Set raw-udp candidate for content" << i;
++			QDomElement candidate = doc()->createElement("candidate");
++			QString ip;
++
++			//Trying to get the address with the most chances to succeed.
++			if (eip != "") //does not seem to work...
++			{
++				ip = eip;
++			}
++			else
++			{
++				QNetworkInterface *interface = new QNetworkInterface();
++				QList<QHostAddress> ips = interface->allAddresses();
++				qSort(ips.begin(), ips.end(), interfaceOrder);
++	
++				if (ips.count() == 0)
++				{
++					qDebug() << "No Internet address found. Are you connected ?";
++					//emit error(NoNetwork);
++					return;
++				}
++				ip = ips[0].toString();
++			}
++			candidate.setAttribute("ip", ip); // ips[0] is not 127.0.0.1 if there is other adresses.
++			int port = client()->jingleSessionManager()->nextRawUdpPort();
++			//qDebug() << "Port =" << port;
++			//qDebug() << "Port =" << QString("%1").arg(port);
++			candidate.setAttribute("port", QString("%1").arg(port));
++			candidate.setAttribute("generation", "0"); // FIXME:I don't know yet what it is.
++			transport.appendChild(candidate);
++			d->session->contents()[i]->bind(QHostAddress(ip), port);
++			//qDebug() << client()->stream().xmlToString(transport, false);
++		}
++		else if (transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++		{
++			//TODO:implement me.
++		}
++		//d->session->contents()[i]->setTransport(transport);
++		jingle.appendChild(d->session->contents()[i]->contentElement());
++	}
++
++	d->iq.appendChild(jingle);
++	//send(d->iq);
++}
++
++
++void JT_JingleAction::contentAccept()
++{
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++
++	qDebug() << "Sending the content-accept to : " << d->session->to().full();
++	
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++	
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "content-accept");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++
++	d->iq.appendChild(jingle);
++	//send(d->iq);
++}
++
++void JT_JingleAction::ringing()
++{
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++
++	qDebug() << "Sending the session-info (ringing) to : " << d->session->to().full();
++	
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++	
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-info");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	
++	QDomElement ring = doc()->createElement("ringing");
++	ring.setAttribute("xmlns", "urn:xmpp:tmp:jingle:apps:audio-rtp:info");
++
++	jingle.appendChild(ring);
++	d->iq.appendChild(jingle);
++
++	//send(d->iq);
++}
++
++void JT_JingleAction::terminate(const JingleReason& r)
++{
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the session-terminate to : " << d->session->to().full();
++	
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++	
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-terminate");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++
++	QDomElement reason = doc()->createElement("reason");
++	QDomElement condition = doc()->createElement("condition");
++
++	QDomElement rReason;
++	switch(r.type())
++	{
++	case JingleReason::Decline :
++		rReason = doc()->createElement("decline");
++		break;
++	case JingleReason::NoReason :
++		rReason = doc()->createElement("no-error");
++		break;
++	case JingleReason::UnsupportedApplications :
++		rReason = doc()->createElement("unsupported-applications");
++		break;
++	default:
++		rReason = doc()->createElement("unknown");
++	}
++
++	d->iq.appendChild(jingle);
++	jingle.appendChild(reason);
++	reason.appendChild(condition);
++	condition.appendChild(rReason);
++	//send(d->iq);
++}
++
++void JT_JingleAction::removeContents(const QStringList& c)
++{
++	// ----------------------------
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the session-terminate to : " << d->session->to().full();
++	
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++	
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "content-remove");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	//---------This par should be in another method (createJingleIQ(...))
++	
++	for (int i = 0; i < c.count(); i++)
++	{
++		QDomElement content = doc()->createElement("content");
++		content.setAttribute("name", c[i]);
++		jingle.appendChild(content);
++	}
++	//FIXME:MUST the 'creator' tag be there ?
++	
++	d->iq.appendChild(jingle);
++
++	//send(d->iq);
++}
++
++void JT_JingleAction::transportInfo(JingleContent *c)
++{
++	QDomElement e = c->transport();
++	// ----------------------------
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the transport-info to : " << d->session->to().full();
++
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "transport-info");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	//---------This part should be in another method (createJingleIQ(...))
++	QString eip = client()->jingleSessionManager()->externalIP();
++
++	if (e.attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++	{
++		QDomElement content = doc()->createElement("content");
++		content.setAttribute("name", c->name());
++		content.setAttribute("creator", d->session->initiator() == d->session->to().full() ? d->session->to().full() : "initiator");
++
++		QDomElement transport = doc()->createElement("transport");
++		transport.setAttribute("xmlns", NS_JINGLE_TRANSPORTS_RAW);
++		
++		QDomElement candidate = doc()->createElement("candidate");
++		QString ip;
++
++		//Trying to get the address with the most chances to succeed.
++		if (eip != "") //does not seem to work.
++		{
++			ip = eip;
++		}
++		else
++		{
++			QNetworkInterface *interface = new QNetworkInterface();
++			QList<QHostAddress> ips = interface->allAddresses();
++			qSort(ips.begin(), ips.end(), interfaceOrder);
++
++			if (ips.count() == 0)
++			{
++				qDebug() << "No Internet address found. Are you connected ?";
++				//emit error(NoNetwork);
++				return;
++			}
++			ip = ips[0].toString();
++		}
++		candidate.setAttribute("ip", ip); // ips[0] is not 127.0.0.1 if there is other adresses.
++		int port = client()->jingleSessionManager()->nextRawUdpPort();
++		//qDebug() << "Port =" << port;
++		//qDebug() << "Port =" << QString("%1").arg(port);
++		candidate.setAttribute("port", QString("%1").arg(port));
++		candidate.setAttribute("generation", "0"); // FIXME:I don't know yet what it is.
++		transport.appendChild(candidate);
++		content.appendChild(transport);
++		jingle.appendChild(content);
++		d->iq.appendChild(jingle);
++		
++		c->bind(QHostAddress(ip), port);
++	}
++	else if (e.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++	{
++		qDebug() << "ICE-UDP is not implemented yet.";
++	}
++	else
++	{
++		qDebug() << "Unsupported protocol (" << e.attribute("xmlns") << ")";
++		return;
++	}
++
++	//send(d->iq);
++}
++
++void JT_JingleAction::trying(const JingleContent& c)
++{
++	QDomElement e = c.transport();
++	// ----------------------------
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the session-info to : " << d->session->to().full();
++
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-info");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	//---------This par should be in another method (createJingleIQ(...))
++	if (e.attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++	{
++		QDomElement trying = doc()->createElement("trying");
++		trying.setAttribute("xmlns", "urn:xmpp:tmp:jingle:transports:raw-udp:info");
++		jingle.appendChild(trying);
++		d->iq.appendChild(jingle);
++	}
++	else if (e.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++	{
++		qDebug() << "ICE-UDP is not implemented yet. (is trying message used with ICE-UDP ??? )";
++	}
++	else
++	{
++		qDebug() << "Unsupported protocol (" << e.attribute("xmlns") << ")";
++		return;
++	}
++
++	//send(d->iq);
++	
++}
++
++void JT_JingleAction::received()
++{
++	// ----------------------------
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the session-info to : " << d->session->to().full();
++
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-info");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	//---------This par should be in another method (createJingleIQ(...))
++	QDomElement received = doc()->createElement("received");
++	
++	//That depends of the session content's transport.
++	//Ice-udp does not need the "receive" informationnal message.
++	received.setAttribute("xmlns", "urn:xmpp:tmp:jingle:transports:raw-udp:info");
++	
++	jingle.appendChild(received);
++	d->iq.appendChild(jingle);
++}
++
++void JT_JingleAction::sessionAccept(const QList<JingleContent*>& contents)
++{
++	// ----------------------------
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the session-accept to : " << d->session->to().full();
++
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-accept");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	//---------This par should be in another method (createJingleIQ(...))
++	
++	for (int i = 0; i < contents.count(); i++)
++	{
++		jingle.appendChild(contents[i]->contentElement());
++	}
++
++	d->iq.appendChild(jingle);
++	qDebug() << "Prepare to send :";
++	client()->stream().xmlToString(d->iq, false);
++
++	//send(d->iq);
++}
++
++bool JT_JingleAction::take(const QDomElement &x)
++{
++	if (!iqVerify(x, d->session->to().full(), id()))
++		return false;
++	
++	setSuccess();
++	emit finished();
++
++	return true;
++}
++
++void JT_JingleAction::onGo()
++{
++	send(d->iq);
++}
++
+diff -Nur iris-1.0.0/src/xmpp/jingle/jingletasks.h iris-1.0.0-023_jingle/src/xmpp/jingle/jingletasks.h
+--- iris-1.0.0/src/xmpp/jingle/jingletasks.h	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jingletasks.h	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,221 @@
++/*
++ * jingletasks.cpp - Tasks for the Jingle specification.
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++#ifndef JINGLE_TASKS
++#define JINGLE_TASKS
++
++#include <QDomElement>
++#include <QUdpSocket>
++
++#include "im.h"
++#include "xmpp_task.h"
++#include "jinglesession.h"
++#include "jinglecontent.h"
++
++namespace XMPP
++{
++	class JingleSession;
++	class JingleReason;
++	
++	/*
++	 * This class is a Task that received all jingle actions and give them to the JingleSessionManager
++	 */
++	class IRIS_EXPORT JT_PushJingleAction : public Task
++	{
++		Q_OBJECT
++	public:
++		JT_PushJingleAction(Task*);
++		~JT_PushJingleAction();
++
++		void onGo();
++		bool take(const QDomElement&);
++		
++		/*
++		 * Returns the next incoming session, this
++		 * method should be called each time the newSessionIncoming()
++		 * SIGNAL is emitted.
++		 */
++		JingleSession *takeNextIncomingSession();
++	signals:
++		/*
++		 * Emitted when a new session is incoming. the JingleSession
++		 * can be retrieved with takeNextIncomingSession()
++		 */
++		void newSessionIncoming();
++
++		/*
++		 * Emitted when a peer wants to remove 1 or more content(s)
++		 * from a session (content-remove action). It contains the
++		 * session id and a list of the contents to remove.
++		 */
++		void removeContent(const QString&, const QStringList&);
++
++		/*
++		 * Emitted when a peer sends a session information
++		 * (session-info jingle action).
++		 * In the case of RAW UDP transport, a session info can be an
++		 * informational message like "trying" or "received".
++		 * Argument is a QDomElement containing the jingle
++		 * tag (and children).
++		 */
++		void sessionInfo(const QDomElement&);
++
++		/*
++		 * Emitted when a peer sends a transport info.
++		 * In most cases, a transport-info jingle action
++		 * is used to transfer candidate(s).
++		 * Argument is a QDomElement containing the jingle
++		 * tag (and children).
++		 */
++		void transportInfo(const QDomElement&);
++
++		/*
++		 * Emitted when a peer wants to terminate a session
++		 * (session-terminate jingle action)
++		 * Arguments are the session ID and the Reason of the termination.
++		 */
++		void sessionTerminate(const QString&, const JingleReason&);
++
++		/*
++		 * Signal emitted when a session-accept jingle action has been received.
++		 */
++		void sessionAccepted(const QDomElement&);
++	
++	private:
++		class Private;
++		Private *d;
++
++		/* This method is called to acknowledge the stanza's sender.
++		 * before it is called, d->id must be set to the received
++		 * stanza's id.
++		 */
++		void ack();
++
++		/*
++		 * Called when an error iq stanza is received.
++		 * This method should do whatever it must be
++		 * done in the case of an error.
++		 * TODO:Implement me!
++		 */
++		void jingleError(const QDomElement&);
++	};
++
++	/*
++	 * This class is a task which is used to send all
++	 * possible jingle action to a contact, asked by a
++	 * JingleAction.
++	 */
++	class IRIS_EXPORT JT_JingleAction : public Task
++	{
++		Q_OBJECT
++	public:
++		JT_JingleAction(Task*);
++		~JT_JingleAction();
++		
++		void onGo();
++		bool take(const QDomElement&);
++		
++		/*
++		 * Before doing anything, this method must
++		 * be called to set the JingleSession pointer
++		 * so the task has all necessary information.
++		 */
++		void setSession(JingleSession*);
++		
++		/*
++		 * Send a session-initiate jingle action.
++		 * There is no argument as the JingleSession set
++		 * sooner must have all necessary information
++		 * (to, contents and sid)
++		 * In contents list, contents with raw-udp transport
++		 * must have a candidate set.
++		 */
++		void initiate();
++
++		/*
++		 * Send a session-terminate jingle action.
++		 * A reason is given as a parameter.
++		 */
++		void terminate(const JingleReason&);
++
++		/*
++		 * Send a content-accept jingle action.
++		 * TODO:should take a list of contents to accept.
++		 * 	Contents must be what we support, not the
++		 * 	contents we received in the session-initiate
++		 * 	jingle action.
++		 * TODO:(Re)implement me!
++		 */
++		void contentAccept();
++
++		/*
++		 * Send a content-remove jingle action.
++		 * The argument is a list containing the
++		 * content names to remove.
++		 */
++		void removeContents(const QStringList&);
++
++		/*
++		 * Sends a "ringing" informational message.
++		 * FIXME:Ringing is a session-info jingle action.
++		 * 	 It should be sent via a sessionInfo()
++		 * 	 method.
++		 */
++		void ringing();
++
++		/*
++		 * Sends a "trying" informational message.
++		 * FIXME:Same as ringing();
++		 */
++		void trying(const JingleContent&);
++
++		/*
++		 * Sends a "received" informational message.
++		 * FIXME:Same as ringing();
++		 */
++		void received();
++
++		/*
++		 * Sends a transport-info jingle action for a
++		 * content's transport.
++		 * Currently, this class sends candidate(s) for
++		 * the content's transport.
++		 */
++		void transportInfo(JingleContent *c);
++
++		/*
++		 * Sends a session-accept jingle action.
++		 * Once acked, this will mean the session is in the ACTIVE state
++		 */
++		void sessionAccept(const QList<JingleContent*>&);
++		
++	private :
++		class Private;
++		Private *d;
++	signals :
++		/*
++		 * This signal is emitted when the sent jingle
++		 * action has been acknowledged
++		 */
++		void finished();
++	
++	};
++}
++
++#endif
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/client.cpp iris-1.0.0-023_jingle/src/xmpp/xmpp-im/client.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/client.cpp	2011-06-05 23:42:45.000000000 +0200
++++ iris-1.0.0-023_jingle/src/xmpp/xmpp-im/client.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -82,6 +82,7 @@
+ #include "xmpp_ibb.h"
+ #include "xmpp_bitsofbinary.h"
+ #include "filetransfer.h"
++#include "../jingle/jinglesessionmanager.h"
+ 
+ /*#include <stdio.h>
+ #include <stdarg.h>
+@@ -143,6 +144,7 @@
+ 	IBBManager *ibbman;
+ 	BoBManager *bobman;
+ 	FileTransferManager *ftman;
++	JingleSessionManager *jingleman;
+ 	bool ftEnabled;
+ 	QList<GroupChat> groupChatList;
+ };
+@@ -176,6 +178,7 @@
+ 	d->bobman = new BoBManager(this);
+ 
+ 	d->ftman = 0;
++	d->jingleman = 0L;
+ }
+ 
+ Client::~Client()
+@@ -183,6 +186,7 @@
+ 	close(true);
+ 
+ 	delete d->ftman;
++	delete d->jingleman;
+ 	delete d->ibbman;
+ 	delete d->s5bman;
+ 	delete d->root;
+@@ -251,6 +255,25 @@
+ 	return d->ftman;
+ }
+ 
++void Client::setJingleEnabled(bool b)
++{
++	if (b) {
++		if (!d->jingleman)
++			d->jingleman = new JingleSessionManager(this);
++	}
++	else {
++		if (d->jingleman) {
++			delete d->jingleman;
++			d->jingleman = 0L;
++		}
++	}
++}
++
++JingleSessionManager *Client::jingleSessionManager() const
++{
++	return d->jingleman;
++}
++
+ S5BManager *Client::s5bManager() const
+ {
+ 	return d->s5bman;
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_client.h iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_client.h
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_client.h	2011-06-05 23:42:45.000000000 +0200
++++ iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_client.h	2013-02-13 19:48:35.000000000 +0100
+@@ -35,6 +35,7 @@
+ 	class ClientStream;
+ 	class Features;
+ 	class FileTransferManager;
++	class JingleSessionManager;
+ 	class IBBManager;
+ 	class JidLinkManager;
+ 	class LiveRoster;
+@@ -125,6 +126,9 @@
+ 		void setFileTransferEnabled(bool b);
+ 		FileTransferManager *fileTransferManager() const;
+ 
++		void setJingleEnabled(bool b);
++		JingleSessionManager *jingleSessionManager() const;
++
+ 		QString groupChatPassword(const QString& host, const QString& room) const;
+ 		bool groupChatJoin(const QString &host, const QString &room, const QString &nick, const QString& password = QString(), int maxchars = -1, int maxstanzas = -1, int seconds = -1, const Status& = Status());
+ 		void groupChatSetStatus(const QString &host, const QString &room, const Status &);
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_features.cpp iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_features.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_features.cpp	2008-10-04 00:32:26.000000000 +0200
++++ iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_features.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -129,6 +129,41 @@
+ 	return test(ns);
+ }
+ 
++#define FID_JINGLE "urn:xmpp:tmp:jingle:0"
++bool Features::canJingle() const
++{
++       QStringList ns;
++       ns << FID_JINGLE;
++
++       return test(ns);
++}
++
++#define FID_JINGLERTP "urn:xmpp:tmp:jingle:apps:rtp:0"
++bool Features::canJingleRtp() const
++{
++       QStringList ns;
++       ns << FID_JINGLERTP;
++
++       return test(ns);
++}
++#define FID_JINGLERAW "urn:xmpp:jingle:transports:raw-udp:0"
++bool Features::canJingleRaw() const
++{
++       QStringList ns;
++       ns << FID_JINGLERAW;
++
++       return test(ns);
++}
++
++#define FID_JINGLEICE "urn:xmpp:jingle:transports:ice-udp:0"
++bool Features::canJingleIce() const
++{
++       QStringList ns;
++       ns << FID_JINGLEICE;
++
++       return test(ns);
++}
++
+ #define FID_GATEWAY "jabber:iq:gateway"
+ bool Features::isGateway() const
+ {
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_features.h iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_features.h
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_features.h	2007-09-20 20:39:14.000000000 +0200
++++ iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_features.h	2013-02-13 19:48:35.000000000 +0100
+@@ -45,6 +45,10 @@
+ 		bool canMulticast() const;
+ 		bool canGroupchat() const;
+ 		bool canVoice() const;
++		bool canJingle() const;
++		bool canJingleRtp() const;
++		bool canJingleRaw() const;
++		bool canJingleIce() const;
+ 		bool canDisco() const;
+ 		bool canChatState() const;
+ 		bool canCommand() const;
diff --git a/iris-1.0.0-023_jingle.patch b/iris-1.0.0-023_jingle.patch
new file mode 100644
index 0000000..46919a6
--- /dev/null
+++ b/iris-1.0.0-023_jingle.patch
@@ -0,0 +1,3393 @@
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglecontent.cpp iris-1.0.0-023_jingle/src/xmpp/jingle/jinglecontent.cpp
+--- iris-1.0.0/src/xmpp/jingle/jinglecontent.cpp	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglecontent.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,509 @@
++/*
++ * jinglecontent.cpp - Jingle content
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#include "jinglecontent.h"
++
++#include "jinglesession.h"
++
++#include <QTimer>
++#include <QDomElement>
++#include <QUdpSocket>
++
++//----------------------
++// JingleContent
++//----------------------
++
++using namespace XMPP;
++
++
++class JingleContent::Private
++{
++public:
++	QList<QDomElement> payloads; // My payloads.
++	QList<QDomElement> rPayloads; // Responder's payloads.
++	QDomElement bestPayload;
++
++	QDomElement transport;
++	QList<QDomElement> candidates;
++	QString creator;
++	QString name;
++	QString descriptionNS;
++	//The application will access this socket directly, Iris has not to deal with RTP.
++	QUdpSocket *inSocket; //Currently, this is the IN raw-udp socket for this content.
++	QUdpSocket *outSocket; //Currently, this is the OUT raw-udp socket for this content.
++	bool sending;
++	bool receiving;
++	Type type;
++	bool isInitiator;
++	QTimer *outTimer;
++	int tries;
++};
++
++JingleContent::JingleContent()
++: d(new Private())
++{
++	qDebug() << "Creating JingleContent";
++	d->sending = false;
++	d->receiving = false;
++	d->inSocket = 0L;
++	d->outSocket = 0L;
++	d->isInitiator = false;
++	d->tries = 0;
++}
++
++JingleContent::~JingleContent()
++{
++	//delete d->inSocket;
++	//delete d->outSocket;
++	delete d;
++}
++
++QDomElement JingleContent::bestPayload()
++{
++	if (d->bestPayload.isNull())
++	{
++		//Trying to update the best payload.
++		d->bestPayload = bestPayload(d->rPayloads, d->payloads);
++	}
++	return d->bestPayload;
++}
++
++void JingleContent::addCandidate(const QDomElement& c)
++{
++	d->candidates << c;
++}
++
++void JingleContent::addPayloadType(const QDomElement& pl)
++{
++	d->payloads << pl;
++}
++
++void JingleContent::addPayloadTypes(const QList<QDomElement>& pl)
++{
++	d->payloads << pl;
++}
++
++void JingleContent::setPayloadTypes(const QList<QDomElement>& pl)
++{
++	d->payloads.clear();
++	d->payloads = pl;
++}
++
++void JingleContent::setTransport(const QDomElement& t)
++{
++	d->transport = t;
++}
++
++QList<QDomElement> JingleContent::payloadTypes() const
++{
++	return d->payloads;
++}
++
++QDomElement JingleContent::transport() const
++{
++	return d->transport;
++}
++
++void JingleContent::setCreator(const QString& c)
++{
++	d->creator = c;
++}
++
++void JingleContent::setName(const QString& n)
++{
++	d->name = n;
++}
++
++void JingleContent::setDescriptionNS(const QString& desc)
++{
++	d->descriptionNS = desc;
++}
++
++void JingleContent::fromElement(const QDomElement& e)
++{
++	// FIXME:tag order may not always be the same !!!
++	if (e.tagName() != "content")
++		return;
++	d->creator = e.attribute("creator");
++	d->name = e.attribute("name");
++	QDomElement desc = e.firstChildElement();
++	d->descriptionNS = desc.attribute("xmlns");
++	d->type = stringToType(desc.attribute("media"));
++	QDomElement payload = desc.firstChildElement();
++	// This content is created from XML data, that means that it comes from the outside.
++	// So, pyloads are added as responder payloads
++	QList<QDomElement> payloads;
++	while (!payload.isNull())
++	{
++		payloads << payload;
++		payload = payload.nextSiblingElement();
++	}
++	setResponderPayloads(payloads);
++
++	QDomElement transport = desc.nextSiblingElement();
++	d->transport = transport;
++}
++
++QDomElement JingleContent::contentElement()
++{
++	// Create the QDomElement which has to be returned.
++	QDomDocument doc("");
++	
++	QDomElement content = doc.createElement("content");
++	content.setAttribute("creator", d->creator);
++	content.setAttribute("name", d->name);
++	content.setAttribute("sender", "both"); //Setting to default currently, change it !
++	
++	QDomElement description = doc.createElement("description");
++	description.setAttribute("xmlns", d->descriptionNS);
++	description.setAttribute("media", typeToString(d->type));
++
++	for (int i = 0; i < d->payloads.count(); i++)
++	{
++		description.appendChild(d->payloads.at(i));
++	}
++	content.appendChild(description);
++	content.appendChild(d->transport);
++
++	return content;
++}
++
++QString JingleContent::name() const
++{
++	return d->name;
++}
++
++QString JingleContent::descriptionNS() const
++{
++	return d->descriptionNS;
++}
++
++void JingleContent::addTransportInfo(const QDomElement& e)
++{
++	QDomElement transport = e.firstChildElement();
++	if (transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++	{
++		if (d->transport.attribute("pwd") != transport.attribute("pwd"))
++		{
++			qDebug() << "Bad ICE Password !";
++			return;
++		}
++		
++		if (d->transport.attribute("ufrag") != transport.attribute("ufrag"))
++		{
++			qDebug() << "Bad ICE User Fragment !";
++			return;
++		}
++		QDomElement child = transport.firstChildElement();
++		//FIXME:Is it possible to have more than one candidate per transport-info ?
++		//	See Thread "Jingle: multiple candidates per transport-info?" on xmpp-standards.
++		if (child.tagName() == "candidate")
++		{
++			// Just adding the Xml Element.
++			d->candidates << child;
++		}
++	}
++	else if (transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++	{
++		qDebug() << "Adding responder's candidates and connecting to it";
++		d->candidates << transport.firstChildElement();
++		//TODO : Start connection to this candidate.
++		//WARNING : as Jingle specification is not clear,
++		//	    the connexion will be considered as established
++		//	    even without receiving the "received" informational
++		//	    message.
++		startSending(QHostAddress(transport.firstChildElement().attribute("ip")),
++			     transport.firstChildElement().attribute("port").toInt());
++		
++	}
++}
++
++/*FIXME:this as no sense, this content is for RAW UDP only*/
++QString JingleContent::iceUdpPassword()
++{
++	if (d->transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++		return d->transport.attribute("pwd");
++	return "";
++}
++
++/*FIXME:this as no sense, this content is for RAW UDP only*/
++QString JingleContent::iceUdpUFrag()
++{
++	if (d->transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++		return d->transport.attribute("ufrag");
++	return "";
++}
++
++void JingleContent::createUdpInSocket()
++{
++	if (d->transport.attribute("xmlns") != NS_JINGLE_TRANSPORTS_RAW)
++		return;
++	qDebug() << "JingleContent::createUdpInSocket()";
++	
++	if (!d->inSocket)
++		d->inSocket = new QUdpSocket();
++	
++	QHostAddress address(d->transport.firstChildElement().attribute("ip"));
++	int port = d->transport.firstChildElement().attribute("port").toInt();
++	qDebug() << "Bind socket to" << address << ":" << port;
++	if (d->inSocket->bind(/*address, */port))
++		qDebug() << "Socket bound to" << /*address.toString() << ":" <<*/ port;
++	
++	connect(d->inSocket, SIGNAL(readyRead()), this, SLOT(slotRawUdpDataReady()));
++	//emit inSocketReady(); --> also no need of this.
++}
++
++void JingleContent::slotRawUdpDataReady()
++{
++	qDebug() << "slotRawUdpDataReady() :: Data arrived on the socket.";
++	emit dataReceived();
++	setReceiving(true);
++	disconnect(sender(), SIGNAL(readyRead()), this, 0);
++}
++
++QUdpSocket *JingleContent::inSocket()
++{
++	qDebug() << "Getting IN socket from content" << name();
++	return d->inSocket;
++}
++
++QUdpSocket *JingleContent::outSocket()
++{
++	qDebug() << "Getting OUT socket from content" << name();
++	return d->outSocket;
++}
++
++bool JingleContent::sending()
++{
++	return d->sending;
++}
++
++void JingleContent::setSending(bool s)
++{
++	if (d->sending == s)
++		return;
++	d->sending = s;
++	
++	// We do not need to try sending anymore, we have proof that data sending is OK.
++	d->outTimer->stop();
++	delete d->outTimer;
++
++	// If we are also receiving, that's ok, this content is established.
++	if (d->sending && d->receiving)
++	{
++		qDebug() << "setSending : emit established() SIGNAL";
++		emit established();
++	}
++}
++
++bool JingleContent::receiving()
++{
++	return d->receiving;
++}
++
++void JingleContent::setReceiving(bool r)
++{
++	if (d->receiving == r)
++		return;
++	d->receiving = r;
++	if (d->sending && d->receiving)
++	{
++		qDebug() << "setReceiving : emit established() SIGNAL";
++		emit established();
++	}
++}
++
++void JingleContent::startSending()
++{
++	QHostAddress address(transport().firstChildElement().attribute("ip"));
++	int port = transport().firstChildElement().attribute("port").toInt();
++	startSending(address, port);
++}
++
++void JingleContent::startSending(const QHostAddress& address, int port)
++{
++	//This correspond to the trying phase.
++	//Create udp OUT socket
++	if (!d->outSocket)
++		d->outSocket = new QUdpSocket();
++	d->outSocket->connectToHost(address, port);
++	//emit outSocketReady(); --> This signal has no sense anymore, we must prepare rtp sessions when the sockets are both ready.
++	
++	qDebug() << "Sending data to" << address.toString() << ":" << port;
++	//We will start sending "SYN" every 5 seconds for 1 minute until we receive a received informationnal message.
++	slotTrySending();
++	d->outTimer = new QTimer();
++	d->outTimer->setInterval(5000);
++	connect(d->outTimer, SIGNAL(timeout()), this, SLOT(slotTrySending()));
++	//setSending(true); --> set it when the received informationnal message has been received.
++}
++
++void JingleContent::slotTrySending()
++{
++	d->tries++;
++	if (d->tries == 13)
++	{
++		//This content cannot connect, what do we do ?
++		d->outTimer->stop();
++		qDebug() << "JingleContent::slotTrySending : Unable to establish the connection for content" << name();
++	}
++
++	d->outSocket->write(QByteArray("SYN"));
++}
++
++QList<QDomElement> JingleContent::candidates() const
++{
++	return d->candidates;
++}
++
++QString JingleContent::creator() const
++{
++	return d->creator;
++}
++
++void JingleContent::bind(const QHostAddress& address, int port)
++{
++	qDebug() << "Trying to bind socket to" << address.toString() << ":" << port;
++	if (!d->inSocket)
++		d->inSocket = new QUdpSocket();
++	if (d->inSocket->bind(address, port))
++		qDebug() << "Socket bound to" << address.toString() << ":" << port;
++	
++	connect(d->inSocket, SIGNAL(readyRead()), this, SLOT(slotRawUdpDataReady()));
++	
++	//emit inSocketReady();
++}
++
++JingleContent& JingleContent::operator=(const JingleContent &other)
++{
++	d->payloads = other.payloadTypes();
++	d->transport = other.transport();
++	d->candidates = other.candidates();
++	d->creator = other.creator();
++	d->name = other.name();
++	d->descriptionNS = other.descriptionNS();
++	
++	return *this;
++}
++
++void JingleContent::setType(JingleContent::Type t)
++{
++	d->type = t;
++}
++
++JingleContent::Type JingleContent::type() const
++{
++	return d->type;
++}
++
++QString JingleContent::typeToString(JingleContent::Type t)
++{
++	switch(t)
++	{
++	case Video :
++		return "video";
++	case Audio :
++		return "audio";
++	case FileTransfer :
++		return "file transfer";
++	default:
++		return "unknown";
++	}
++}
++
++void JingleContent::setResponderPayloads(const QList<QDomElement>& payloads)
++{
++	qDebug() << "*******Setting responder payloads**********";
++	d->rPayloads = payloads;
++	if (d->payloads.count() != 0) //No, if payloads is empty, we should get the list from the supported payloads. Actually, those payloads should be always set when creating the content.
++	{
++		//Store the best payload to use for this content.
++		//The application will just have to get it from this content.
++		d->bestPayload = bestPayload(d->rPayloads, d->payloads);
++	}
++}
++
++QList<QDomElement> JingleContent::responderPayloads() const
++{
++	return d->rPayloads;
++}
++
++JingleContent::Type JingleContent::stringToType(const QString& s)
++{
++	if (s == "video")
++		return Video;
++	else if (s == "audio")
++		return Audio;
++	else if (s == "file transfer")
++		return FileTransfer;
++	else
++		return Unknown;
++}
++
++QDomElement JingleContent::bestPayload(const QList<QDomElement>& payload1, const QList<QDomElement>& payload2)
++{
++	//FIXME : this is not the best algorithm to determine which one is the better.
++	// |-------|
++	// | a | c |
++	// +---+---+
++	// | b | b |
++	// +---+---+
++	// | d | e |
++	// +---+---+
++	// | c | a |
++	// |-------|
++	//  --> In that case, payload a will be chosen but payload b would be the best choice.
++	for (int i = 0; i < payload1.count(); i++)
++	{
++		for (int j = 0; j < payload2.count(); j++)
++		{
++			if (samePayload(payload1[i], payload2[j]))
++				return payload1[i];
++		}
++	}
++	qDebug() << "Returns QDomElement !";
++	return QDomElement();
++}
++
++bool JingleContent::samePayload(const QDomElement& p1, const QDomElement& p2)
++{
++	// Checking payload-type attributes
++	if (!p1.hasAttribute("id") || !p2.hasAttribute("id"))
++		return false;
++	if (p1.attribute("id") != p2.attribute("id"))
++		return false;
++	int id = p1.attribute("id").toInt();
++	if ((id >= 96) && (id <= 127)) //dynamic payloads, "name" attribute must be there
++	{
++		if (!p1.hasAttribute("name") || !p2.hasAttribute("name"))
++			return false;
++		if (p1.attribute("name") != p2.attribute("name"))
++			return false;
++	}
++	if (p1.hasAttribute("channels") && p2.hasAttribute("channels"))
++		if (p1.attribute("channels") != p2.attribute("channels"))
++			return false;
++	if (p1.hasAttribute("clockrate") && p2.hasAttribute("clockrate"))
++		if (p1.attribute("clockrate") != p2.attribute("clockrate"))
++			return false;
++	// Parameters are informative, even if they differ, the payload is stil the same.
++	qDebug() << "Payloads are the same.";
++	return true;
++}
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglecontent.h iris-1.0.0-023_jingle/src/xmpp/jingle/jinglecontent.h
+--- iris-1.0.0/src/xmpp/jingle/jinglecontent.h	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglecontent.h	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,211 @@
++/*
++ * jinglecontent.cpp - Jingle content
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++#ifndef JINGLE_CONTENT_H
++#define JINGLE_CONTENT_H
++
++#include <QObject>
++
++#include "im.h"
++
++class QHostAddress;
++class QDomElement;
++class QUdpSocket;
++namespace XMPP
++{
++	/*
++	 * This class contains all information about a particular content in a jingle session.
++	 * It also has the socket that will be used for streaming.
++	 */
++	//This is the Raw-udp jingle content.
++	class JingleContent : public QObject
++	{
++		Q_OBJECT
++	public:
++		JingleContent();
++		~JingleContent();
++
++		/**
++		 * Defines the content type, this represesent the media attribute.
++		 */
++		enum Type {
++			Audio = 0,
++			Video,
++			FileTransfer,
++			Unknown
++		};
++
++		/*
++		 * Adds a payload type to this content.
++		 */
++		void addPayloadType(const QDomElement&);
++		
++		/*
++		 * Adds a payload type list to this content.
++		 */
++		void addPayloadTypes(const QList<QDomElement>&);
++
++		/*
++		 * Overwrite the current payload types list with this one.
++		 */
++		void setPayloadTypes(const QList<QDomElement>&);
++
++		/*
++		 * Sets the transport for this content.
++		 */
++		void setTransport(const QDomElement&);
++
++		/*
++		 * Set the content type, this will set the "media" attribute of
++		 * the content tag in the stanza.
++		 */
++		void setType(Type);
++
++		/*
++		 * Gets the type of this content.
++		 */
++		Type type() const;
++
++		/*
++		 * Set the creator of this content, the creator only accept 2 values :
++		 * 	* initiator
++		 * 	* responder
++		 * TODO:An enum should be created to avoid confusion
++		 */
++		void setCreator(const QString&);
++		
++		/*
++		 * Set this content's name
++		 */
++		void setName(const QString&);
++
++		/*
++		 * Set this content description namespace.
++		 * The only one supported currently is
++		 * 	NS
++		 */
++		void setDescriptionNS(const QString&);
++
++		/*
++		 * Returns the payload type list. those payloads are
++		 * our payloads if in Pending state or the content
++		 * used payloads if in Active state. (TODO)
++		 */
++		QList<QDomElement> payloadTypes() const;
++
++		/*
++		 * Returns the transport XML element for this content.
++		 */
++		QDomElement transport() const;
++
++		/*
++		 * Fill this content from a QDomElement.
++		 * The payloads in this QDomElement will be considered as the responder's
++		 * TODO:add an argument to tell the method if those payloads are our's or
++		 * responder's payloads.
++		 */
++		void fromElement(const QDomElement&);
++
++		/*
++		 * Return a QDomElement with the content element and all it's children
++		 * so it's ready to be sent.
++		 */
++		QDomElement contentElement();
++
++		/*
++		 * Returns a list with the available candidates for this content.
++		 * TODO:should return the used candidate when in Active state.
++		 */
++		QList<QDomElement> candidates() const;
++
++		/*
++		 * Adds a candidate to this content. Doing so will add this content(s)
++		 * to the transport when calling contentElement()
++		 */
++		void addCandidate(const QDomElement&);
++		
++		/*
++		 * Adds transport info (mostly a candidate). Doing so will try to
++		 * connect to this candidate.
++		 */
++		void addTransportInfo(const QDomElement&);
++		void createUdpInSocket();
++		
++		QString creator() const;
++		QString name() const;
++		QString descriptionNS() const;
++		QString iceUdpPassword();
++		QString iceUdpUFrag();
++		QUdpSocket *inSocket();
++		QUdpSocket *outSocket();
++		bool sending();
++		void setSending(bool);
++		bool receiving();
++		void setReceiving(bool);
++
++		void startSending();
++		void startSending(const QHostAddress&, int);
++
++		void bind(const QHostAddress&, int);
++		
++		JingleContent& operator=(const JingleContent&);
++		
++		QString typeToString(Type);
++		Type stringToType(const QString& s);
++
++		void setResponderPayloads(const QList<QDomElement>&);
++		QList<QDomElement> responderPayloads() const;
++
++		QDomElement bestPayload();
++
++	public slots:
++		void slotRawUdpDataReady();
++
++		void slotTrySending();
++
++	signals:
++
++		// Emitted when the content is ready to send data to try to connect.
++		void needData(XMPP::JingleContent*);
++		
++		// Emitted when the IN socket is ready to receive data (it is bound).
++		// Can be used to prepare a rtp session with the socket.
++		void inSocketReady();
++		
++		// Emitted when the OUT socket is ready to send data (it is connected).
++		// Can be used to prepare a rtp session with the socket.
++		void outSocketReady();
++
++		/**
++		 * Emitted when sending and receiving streams have been established for this content 
++		 */
++		void established();
++
++		void dataReceived();
++
++	private:
++		class Private;
++		Private *d;
++		
++		QDomElement bestPayload(const QList<QDomElement>&, const QList<QDomElement>&);
++		bool samePayload(const QDomElement&, const QDomElement&);
++	};
++}
++
++#endif
+diff -Nur iris-1.0.0/src/xmpp/jingle/jingle.pri iris-1.0.0-023_jingle/src/xmpp/jingle/jingle.pri
+--- iris-1.0.0/src/xmpp/jingle/jingle.pri	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jingle.pri	2013-02-14 00:23:47.000000000 +0100
+@@ -0,0 +1,14 @@
++INCLUDEPATH *= $$PWD/../..
++DEPENDPATH *= $$PWD/../..
++
++HEADERS += \
++	$$PWD/jinglecontent.h \
++	$$PWD/jinglesession.h \
++	$$PWD/jinglesessionmanager.h \
++	$$PWD/jingletasks.h
++
++SOURCES += \
++	$$PWD/jinglecontent.cpp \
++	$$PWD/jinglesession.cpp \
++	$$PWD/jinglesessionmanager.cpp \
++	$$PWD/jingletasks.cpp
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglesession.cpp iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesession.cpp
+--- iris-1.0.0/src/xmpp/jingle/jinglesession.cpp	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesession.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,665 @@
++/*
++ * jinglesession.cpp - Jingle session
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#include <QString>
++#include <QUdpSocket>
++
++#include "jinglesession.h"
++#include "jinglesessionmanager.h"
++
++using namespace XMPP;
++
++static QString genSid()
++{
++	QString s;
++	int id_seed = rand() % 0xffff;
++	s.sprintf("a%x", id_seed);
++	return s;
++}
++
++class JingleSession::Private
++{
++public:
++	Jid to;
++	QList<JingleContent*> contents;
++	Task *rootTask;
++	JingleSessionManager *jingleSessionManager;
++	QString sid;
++	QString initiator;
++	State state;
++	QStringList contentsToRemove;
++	QStringList transports;
++	bool responderTrying;
++	QList<JT_JingleAction*> actions;
++	bool allContentsConnected;
++	bool userAcceptedSession;
++};
++
++JingleSession::JingleSession(Task *t, const Jid &j)
++: d(new Private)
++{
++	qDebug() << "Creating XMPP::JingleSession";
++	d->to = j;
++	d->rootTask = t;
++	d->jingleSessionManager = t->client()->jingleSessionManager();
++	d->state = Pending;
++	d->responderTrying = false;
++	d->allContentsConnected = false;
++	d->userAcceptedSession = false;
++}
++
++JingleSession::~JingleSession()
++{
++	delete d;
++}
++
++void JingleSession::addContent(JingleContent *c)
++{
++	d->contents << c;
++	connect(c, SIGNAL(dataReceived()), this, SLOT(slotReceivingData()));
++	if (initiator() != d->rootTask->client()->jid().full())
++		connect(c, SIGNAL(established()), this, SLOT(slotContentConnected())); //Only do that if we are not the initiator.
++}
++
++void JingleSession::addContents(const QList<JingleContent*>& l)
++{
++	for (int i = 0; i < l.count(); i++)
++	{
++		d->contents << l[i];
++		connect(l[i], SIGNAL(dataReceived()), this, SLOT(slotReceivingData()));
++		if (initiator() != d->rootTask->client()->jid().full())
++			connect(l[i], SIGNAL(established()), this, SLOT(slotContentConnected()));
++	}
++}
++
++Jid JingleSession::to() const
++{
++	return d->to;
++}
++
++QList<JingleContent*> JingleSession::contents() const
++{
++	return d->contents;
++}
++
++void JingleSession::start()
++{
++	// Generate session ID
++	d->sid = genSid();
++
++	/*qDebug() << "There are" << contents().count() << "contents : ";
++	for (int i = 0; i < contents().count(); i++)
++	{
++		qDebug() << i << ":";
++		qDebug() << d->rootTask->client()->stream().xmlToString(contents()[i]->contentElement(), true);
++	}*/
++
++	JT_JingleAction *iAction = new JT_JingleAction(d->rootTask);
++	d->actions << iAction;
++	iAction->setSession(this);
++	connect(iAction, SIGNAL(finished()), this, SLOT(slotAcked()));
++	iAction->initiate();
++	iAction->go(true);
++	/*for (int i = 0; i < contents().count(); i++)
++	{
++		if (contents()[i]->transport().attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++		{
++			qDebug() << "Create IN socket for" << contents()[i]->name();
++			//qDebug("Content Adress : %x\n", (unsigned int) contents()[i]);
++			//contents()[i]->createUdpInSocket(); --> should be done by the JT_JingleAction::initiate().
++		}
++	}*/
++}
++
++void JingleSession::slotAcked()
++{
++	//Should be autamtically deleted by Iris.
++	/*if (!sender())
++	{
++		qDebug() << "Sender is NULL !";
++		return;
++	}
++	deleteAction(static_cast<JT_JingleAction*>(sender()));*/
++}
++
++void JingleSession::deleteAction(JT_JingleAction* a)
++{
++	//Don't delete tasks, iris will take care of it.
++	/*for (int i = 0; i < d->actions.count(); i++)
++	{
++		if (d->actions[i] == a)
++		{
++			delete d->actions.takeAt(i);
++			break;
++		}
++	}*/
++}
++
++void JingleSession::slotContentConnected()
++{
++	qDebug() << "---------------- void JingleSession::slotContentConnected() : called";
++	bool allOk = true;
++	// Checking if all contents are connected.
++	for (int i = 0; i < contents().count(); i++)
++	{
++		if (!contents()[i]->sending() || !contents()[i]->receiving())
++		{
++			allOk = false;
++			break;
++		}
++	}
++	
++	if (!allOk)
++	{
++		qDebug() << "Not All ok !!! --> Not switching to ACTIVE state.";
++		disconnect(sender(), 0, this, 0);
++		return;
++	}
++	else
++		d->allContentsConnected = true;
++	
++	if (!d->userAcceptedSession)
++	{
++		qDebug() << "User did not accept the session yet.";
++		disconnect(sender(), 0, this, 0);
++		return;
++	}
++	
++	/*qDebug() << initiator() << "=?=" << d->rootTask->client()->jid().full();
++	if (initiator() == d->rootTask->client()->jid().full())
++	{
++		// In this case, we must not send session-accept and wait for it.
++		qDebug() << "I'm the initiator, it's not me who must accept the session.";
++		disconnect(sender(), 0, this, 0);
++		return;
++	}*/
++
++	acceptSession();
++
++	disconnect(sender(), 0, this, 0);
++}
++
++void JingleSession::sessionAccepted(const QDomElement& x)
++{
++	qDebug() << "void JingleSession::sessionAccepted(const QDomElement& x) called";
++	QDomElement content = x.firstChildElement();
++	
++	while (!content.isNull())
++	{
++		JingleContent *c = contentWithName(content.attribute("name"));
++		QList<QDomElement> payloads;
++		QDomElement pType = content.firstChildElement().firstChildElement();
++		//		    content    description         payload-type
++		while (!pType.isNull())
++		{
++			payloads << pType;
++			pType = pType.nextSiblingElement();
++		}
++		c->setResponderPayloads(payloads);
++		qDebug() << "Best payload name :" << c->bestPayload().attribute("name");
++		content = content.nextSiblingElement();
++	}
++	d->state = Active;
++
++	qDebug() << "Ok, we switched to ACTIVE state, starting to stream.";
++	
++	emit stateChanged();
++}
++
++void JingleSession::slotSessionAcceptAcked()
++{
++	d->state = Active;
++
++	if (sender())
++		deleteAction(static_cast<JT_JingleAction*>(sender()));
++	qDebug() << "Ok, we switched to ACTIVE state, starting to stream.";
++	emit stateChanged();
++}
++
++void JingleSession::slotRawUdpDataReady()
++{/*
++	JingleContent *content = (JingleContent*) sender();
++	//qDebug("Content Adress : %x\n", (unsigned int) content);
++	if (content == NULL)
++	{
++		qDebug() << "Null Jingle content, there is a problem";
++		return;
++	}
++	if (d->state == Pending)
++	{
++		content->setReceiving(true);
++		// We check if each contents is receiving AND sending.
++		// In this case, the state can be changed to Active (should emit active() signal)
++		bool changeState = true;
++		for (int i = 0; i < contents().count(); i++)
++		{
++			if ((!contents()[i]->receiving()) || (!contents()[i]->sending()))
++			{
++				changeState = false;
++				break;
++			}
++		}
++		if (changeState)
++			d->state = Active;
++	}
++	QByteArray datagram;
++	QHostAddress address;
++	quint16 port;
++	datagram.resize(content->socket()->pendingDatagramSize());
++	content->socket()->readDatagram(datagram.data(), datagram.size(), &address, &port);
++	qDebug() << "Receiving data for content" << content->name() << "from" << address.toString() << ":" << port << ":";
++	qDebug() << datagram;
++
++	// Send "received" informationnal message. --> No, doesn't.
++	//JT_JingleAction *rAction = new JT_JingleAction(d->rootTask);
++	//connect(rAction, SIGNAL(finished()), this, SLOT(slotReceivedAcked()));
++	//rAction->setSession(this);
++	//rAction->received();
++*/
++}
++
++void JingleSession::acceptSession()
++{
++	qDebug() << "JingleSession::acceptSession() : called";
++
++	if (d->allContentsConnected)
++	{
++		//Accept session.
++		qDebug() << "Ok, all contents connected and session accepted by the user ! let's accept the session.";
++		// Create all contents to send in the session-accept.
++		QList<JingleContent*> contentList;
++		for (int i = 0; i < contents().count(); i++)
++		{
++			qDebug() << "setting right information in the content" << contents()[i]->name();
++			// First, set our supported payload-types.
++			JingleContent *c = new JingleContent();
++			c->setType(contents()[i]->type());
++			c->setPayloadTypes(c->type() == JingleContent::Audio ?
++						d->jingleSessionManager->supportedAudioPayloads() :
++						d->jingleSessionManager->supportedVideoPayloads());
++			c->setDescriptionNS(contents()[i]->descriptionNS());
++			c->setName(contents()[i]->name());
++			c->setCreator(contents()[i]->creator());
++			c->setTransport(contents()[i]->transport().cloneNode(false).toElement()); //We don't need the child nodes.
++			contentList << c;
++	
++			// Then, set the corresponding candidate for ICE-UDP (let's see later)
++			// TODO:implement me !
++		}
++	
++		qDebug() << "Sending session-accept action.";
++		JT_JingleAction *sAction = new JT_JingleAction(d->rootTask);
++		d->actions << sAction;
++		sAction->setSession(this);
++		connect(sAction, SIGNAL(finished()), this, SLOT(slotSessionAcceptAcked()));
++		sAction->sessionAccept(contentList);
++		sAction->go(true);
++	}
++	else
++	{
++		qDebug() << "d->allContentsConnected is FALSE !!!";
++	}
++
++	d->userAcceptedSession = true;
++}
++
++void JingleSession::acceptContent()
++{
++	//TODO:Implement me !
++	//JT_JingleAction *tAction = new JT_JingleAction(d->rootTask);
++	//tAction->setSession(this);
++	//tAction->contentAccept();
++}
++
++void JingleSession::removeContent(const QStringList& c)
++{
++	// Removing only existing contents.
++	for (int i = 0; i < c.count(); i++)
++	{
++		for (int j = 0; j < contents().count(); j++)
++		{
++			if (c.at(i) == contents()[j]->name())
++			{
++				d->contentsToRemove << c[i];
++			}
++		}
++	}
++	if (d->contentsToRemove.count() <= 0)
++		return;
++	
++	//d->contents.removeAt(i); //Or do it in the slotRemoveAcked() ?? --> Yes, we will remove all contents in d->contentsToRemove from d->contents when acked.
++	JT_JingleAction *rAction = new JT_JingleAction(d->rootTask);
++	d->actions << rAction;
++	rAction->setSession(this);
++	connect(rAction, SIGNAL(finished()), this, SLOT(slotRemoveAcked()));
++	rAction->removeContents(d->contentsToRemove);
++	rAction->go(true);
++}
++
++void JingleSession::removeContent(const QString& c) // Provided for convenience, may disappear.
++{
++/*
++ * From Jingle Specification : 
++ * A client MUST NOT return an error upon receipt of a 'content-remove' action for a content
++ * type that is received after a 'content-remove' action has been sent but before the action
++ * has been acknowledged by the peer. 
++ * 
++ * If the content-remove results in zero content types for the session, the entity that receives
++ * the content-remove SHOULD send a session-terminate action to the other party (since a session
++ * with no content types is void).
++ */
++	bool found = false;
++	//if (d->state != Active) /*FIXME:Should be if (d->state == Pending)*/
++	{
++		// FIXME:whatever the state is, the same thing will be done here...
++		// Checking if that content exists.
++		int i = 0;
++		for ( ; i < contents().count(); i++)
++		{
++			if (contents()[i]->name() == c)
++			{
++				found = true;
++				break;
++			}
++		}
++		if (!found)
++		{
++			qDebug() << "This content does not exists for this session (" << c << ")";
++			return;
++		}
++		JT_JingleAction *rAction = new JT_JingleAction(d->rootTask);
++		d->actions << rAction;
++		connect(rAction, SIGNAL(finished()), this, SLOT(slotRemoveAcked()));
++		rAction->setSession(this);
++		d->contentsToRemove << c;
++		rAction->removeContents(d->contentsToRemove);
++		rAction->go(true);
++	}
++}
++
++void JingleSession::slotRemoveAcked()
++{
++	JT_JingleAction *rAction = (JT_JingleAction*) sender();
++	if (rAction != 0)
++		deleteAction(static_cast<JT_JingleAction*>(sender()));
++	else
++		return;
++	// Remove contents from the d->contents
++	for (int i = 0; i < d->contentsToRemove.count(); i++)
++	{
++		for (int j = 0; j < contents().count(); j++)
++		{
++			if (d->contentsToRemove[i] == contents()[j]->name())
++			{
++				d->contents.removeAt(j);
++				break;
++			}
++		}
++	}
++	d->contentsToRemove.clear();
++
++	//else if (d->state == Active)
++	//	emit stopSending(d->contentsToRemove);
++}
++
++void JingleSession::ring()
++{
++	JT_JingleAction *rAction = new JT_JingleAction(d->rootTask);
++	d->actions << rAction;
++	connect(rAction, SIGNAL(finished()), this, SLOT(slotAcked()));
++	rAction->setSession(this);
++	rAction->ringing();
++	rAction->go(true);
++}
++
++void JingleSession::setSid(const QString& s)
++{
++	d->sid = s;
++}
++
++QString JingleSession::sid() const
++{
++	return d->sid;
++}
++
++void JingleSession::setInitiator(const QString& init)
++{
++	d->initiator = init;
++}
++
++void JingleSession::addContent(const QDomElement& content)
++{
++	JingleContent *c = new JingleContent();
++	c->fromElement(content);
++	d->contents << c;
++	
++	if (initiator() != d->rootTask->client()->jid().full())
++		connect(c, SIGNAL(established()), this, SLOT(slotContentConnected()));
++	connect(c, SIGNAL(dataReceived()), this, SLOT(slotReceivingData()));
++}
++
++void JingleSession::sessionTerminate(const JingleReason& r)
++{
++//FIXME:should Take an QDomElement as argument, the application should implement this
++//class itself and be able to return the right QDomElement when calling this method
++	JT_JingleAction *tAction = new JT_JingleAction(d->rootTask);
++	d->actions << tAction;
++	tAction->setSession(this);
++	connect(tAction, SIGNAL(finished()), this, SLOT(slotSessTerminated()));
++	tAction->terminate(r);
++	tAction->go(true);
++}
++
++QString JingleSession::initiator() const
++{
++	return d->initiator;
++}
++
++//TODO:maybe change the name of this function.
++void JingleSession::startNegotiation()
++{
++	/* TODO:
++	 * 	For each transport in each contents, I must send all possible candidates.
++	 * 	Those candidates can be found without the help of the application.
++	 */
++	qDebug() << "Start Negotiation : ";
++	for (int i = 0; i < d->contents.count(); i++)
++	{
++		if (d->contents[i]->transport().attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++		{
++			qDebug() << "    ICE-UDP";
++			sendIceUdpCandidates();
++		}
++		else if (d->contents[i]->transport().attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++		{
++			qDebug() << d->contents[i]->name() << "    RAW-UDP";
++			startRawUdpConnection(d->contents[i]);
++		}
++	}
++}
++
++JingleContent *JingleSession::contentWithName(const QString& n)
++{
++	qDebug() << "There are" << d->contents.count() << "contents";
++	for (int i = 0; i < d->contents.count(); i++)
++	{
++		if (d->contents.at(i)->name() == n)
++			return d->contents[i];
++	}
++	return 0;
++}
++
++void JingleSession::setTo(const Jid& to)
++{
++	d->to = to;
++}
++
++void JingleSession::sendIceUdpCandidates()
++{
++	qDebug() << "Sending ice-udp candidates (Not Implemented Yet)";
++	/*JT_JingleAction *cAction = new JT_JingleAction(d->rootTask);
++	cAction->setSession(this);
++	QDomDocument doc("");
++	QDomElement candidate = doc.createElement("candidate");
++	candidate.setAttribute("foo", "bar");
++	//cAction->sendCandidate(candidate);
++	// --> Or better : sendTransportInfo(QDomElement transport);*/
++}
++
++void JingleSession::startRawUdpConnection(JingleContent *c)
++{
++	QDomElement e = c->transport();
++	qDebug() << "Start raw-udp connection (still 'TODO') for content" << c->name();
++	
++	connect(c, SIGNAL(needData(XMPP::JingleContent*)), this, SIGNAL(needData(XMPP::JingleContent*)));
++	//FIXME:This signal should not go trough JingleSession and be used directly with the JingleContent by the application.
++	c->startSending();
++
++	//Sending my own candidate:
++	JT_JingleAction *cAction = new JT_JingleAction(d->rootTask);
++	d->actions << cAction;
++	connect(cAction, SIGNAL(finished()), this, SLOT(slotAcked()));
++	cAction->setSession(this);
++	cAction->transportInfo(c);
++	cAction->go(true);
++}
++
++void JingleSession::slotSessTerminated()
++{
++	qDebug() << "JingleSession::slotSessTerminated() called !";
++	if (sender())
++		deleteAction(static_cast<JT_JingleAction*>(sender()));
++	qDebug() << "Emit terminated() signal";
++	emit terminated();
++}
++
++void JingleSession::addSessionInfo(const QDomElement& e)
++{
++	QString info = e.tagName();
++	if (info == "trying")
++	{
++		d->responderTrying = true;
++	}
++	else if (info == "received")
++	{
++		//FIXME:For what Content do we receive that info ?
++		//How do I know all content's connections are established, in both directions ?
++		//What if it isn't the case ?
++
++		// We consider every ports are opened, no firewall (that's the specification that tells us that.)
++		for (int i = 0; i < contents().count(); i++)
++		{
++			//We tell the content that it is able to send data.
++			contents()[i]->setSending(true);
++		}
++	}
++}
++
++void JingleSession::addTransportInfo(const QDomElement& e)
++{
++	// this should really depend on the transport used...
++	qDebug() << "Transport info for content named" << e.attribute("name");
++	
++	JingleContent *content = contentWithName(e.attribute("name"));
++	
++	qDebug() << "Found content with address" << (int*) content;
++	
++	connect(content, SIGNAL(needData(XMPP::JingleContent*)), this, SIGNAL(needData(XMPP::JingleContent*)));
++	content->addTransportInfo(e);
++	
++	//If it is a candidate, we try to connect.
++	//FIXME:is a transport-info always a candidate ? --> Currently, we consider this can only a candidate.
++	//TODO:There should be a JingleTransport Class as the transport will be used everywhere
++	//	Also, we could manipulate the QDomElement
++	QDomElement candidate = e.firstChildElement().firstChildElement(); //This is the candidate.
++}
++
++JingleSession::State JingleSession::state() const
++{
++	return d->state;
++}
++
++void JingleSession::slotReceivingData()
++{
++	// Whatever the sender content is, we send the same received informational message.
++	// That's from the raw-udp specification, later, we will have to do fifferent things
++	// here depending on the transport method used in the sender content.
++	
++	JT_JingleAction *rAction = new JT_JingleAction(d->rootTask);
++	d->actions << rAction;
++	connect(rAction, SIGNAL(finished()), this, SLOT(slotAcked()));
++	rAction->setSession(this);
++	rAction->received();
++	rAction->go(true);
++}
++
++
++
++//--------------------------
++// JingleReason
++//--------------------------
++
++
++class JingleReason::Private
++{
++public:
++	QString reasonText;
++	Type type;
++};
++
++JingleReason::JingleReason()
++: d(new Private)
++{
++	d->reasonText = "";
++	d->type = NoReason;
++}
++
++JingleReason::JingleReason(JingleReason::Type type, const QString& text)
++: d(new Private)
++{
++	d->reasonText = text;
++	d->type = type;
++}
++
++JingleReason::~JingleReason()
++{
++
++}
++
++void JingleReason::setText(const QString& r)
++{
++	d->reasonText = r;
++}
++
++void JingleReason::setType(JingleReason::Type t)
++{
++	d->type = t;
++}
++
++QString JingleReason::text() const
++{
++	return d->reasonText;
++}
++
++JingleReason::Type JingleReason::type() const
++{
++	return d->type;
++}
++
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglesession.h iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesession.h
+--- iris-1.0.0/src/xmpp/jingle/jinglesession.h	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesession.h	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,343 @@
++/*
++ * jinglesession.cpp - Jingle session
++ * 
++ * This class defines a Jingle Session which contains all information about the session.
++ * This is here that the state machine is and where almost everything is done for a session.
++ * 
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++#ifndef JINGLE_SESSION
++#define JINGLE_SESSION
++
++#include <QObject>
++#include <QString>
++#include <QDomElement>
++
++#define NS_JINGLE "urn:xmpp:tmp:jingle:0"
++#define NS_JINGLE_TRANSPORTS_RAW "urn:xmpp:tmp:jingle:transports:raw-udp:0"
++#define NS_JINGLE_TRANSPORTS_ICE "urn:xmpp:tmp:jingle:transports:ice-udp:0"
++#define NS_JINGLE_APPS_RTP "urn:xmpp:tmp:jingle:apps:rtp:0"
++
++#define IRIS_EXPORT
++
++#include "im.h"
++//#include "xmpp_client.h"
++//#include "xmpp_jid.h"
++#include "jingletasks.h"
++
++namespace XMPP
++{
++	/*
++	 * This class defines a jingle reason used when sending
++	 * a session-terminate jingle action.
++	 */
++	class IRIS_EXPORT JingleReason
++	{
++	public:
++		/*
++		 * Default constructor : create a No Reason reason with no text.
++		 */
++		JingleReason();
++		enum Type {
++			Decline = 0,
++			Busy,
++			UnsupportedApplications,
++			NoReason
++		};
++		/*
++		 * Creates a reason with a type and a text reason.
++		 */
++		JingleReason(JingleReason::Type, const QString& text = QString());
++		~JingleReason();
++		
++		//static Type stringToType(const QString&);
++
++		void setType(Type);
++		void setText(const QString&);
++		Type type() const;
++		QString text() const;
++	private:
++		class Private;
++		Private *d;
++	};
++
++	class JingleContent;
++	class JT_JingleAction;
++	class JT_PushJingleSession;
++
++	class IRIS_EXPORT JingleSession : public QObject
++	{
++		Q_OBJECT
++	public:
++		JingleSession();
++		JingleSession(Task*, const Jid&);
++		~JingleSession();
++
++		/*
++		 * Adds a content to the session.
++		 * Currently, the content is just added in the contents list.
++		 * TODO: addContent should add a content even when the session
++		 * is in ACTIVE state so the session is modified with a content-add action.
++		 */
++		void addContent(JingleContent*);
++
++		/*
++		 * Same as above but the content is in a QDomElement form.
++		 * For convenience.
++		 */
++		void addContent(const QDomElement&);
++
++		/*
++		 * Adds multiple contents to the session. It is advised
++		 * to use this method instead of addContent() even for
++		 * one content.
++		 */
++		void addContents(const QList<JingleContent*>&);
++
++		/* 
++		 * Adds session information to the session
++		 * (used to inform the session that a "received"
++		 * informational message has been received for eg.)
++		 * Argument is a QDomElement containing the child(s -- TODO)
++		 * of the jingle tag in a jingle stanza.
++		 */
++		void addSessionInfo(const QDomElement&);
++
++		/*
++		 * Adds transport info to the session.
++		 * Mostly, it adds a candidate to the session
++		 * and the session starts to try to connect to it.
++		 * Argument is a QDomElement containing the child(s -- TODO)
++		 * of the jingle tag in a jingle stanza.
++		 */
++		void addTransportInfo(const QDomElement&);
++
++		/*
++		 * Sends a content-accept jingle action.
++		 * Not used yet, may be removed.
++		 */
++		void acceptContent();
++
++		/*
++		 * Sends a session-accept jingle action.
++		 * Not used yet, may be removed.
++		 */
++		void acceptSession();
++
++		/*
++		 * Sends a remove-content jingle action with the content
++		 * name given as an argument.
++		 */
++		void removeContent(const QString&);
++
++		/*
++		 * Sends a remove-content jingle action with the contents
++		 * name given as an argument.
++		 * Prefer this method instead of removeContent(const QString&);
++		 */
++		void removeContent(const QStringList&);
++
++		/*
++		 * Sends a session-terminate jingle action with the reason r.
++		 * Once the responder sends the acknowledgement stanza, the
++		 * signal terminated() is emitted.
++		 */
++		void sessionTerminate(const JingleReason& r = JingleReason());
++
++		/*
++		 * Sends a ringing informational message.
++		 * FIXME:Would be better to use the sessionInfo() method.
++		 */
++		void ring();
++		
++		/*
++		 * Returns the Jid of the other peer with whom the session is established.
++		 */
++		Jid to() const;
++
++		/*
++		 * Returns the contents of this session.
++		 * In Pending state, it should return contents sent by the other peer.
++		 * In Active state, it should return contents being used.
++		 * This is right as we know which contents we do support.
++		 */
++		QList<JingleContent*> contents() const;
++
++		/*
++		 * Starts the session by sending a session-initiate jingle action.
++		 * if a SID has been set, it will be overwritten by a new generated one.
++		 */
++		void start();
++		
++		/* This method sets the SID.
++		 * For an incoming session, the sid must be set and not
++		 * generated randomly.
++		 * Calling the start method after this one will change the SID
++		 */
++		void setSid(const QString&);
++
++		/*
++		 * Sets peer's Jid.
++		 */
++		void setTo(const Jid&);
++
++		/*
++		 * Sets the initiator Jid.
++		 * This can be already set if a session is redirected.
++		 * Session redirection is NOT supported yet.
++		 */
++		void setInitiator(const QString&); //Or const Jid& ??
++
++		/*
++		 * Return initiator Jid.
++		 */
++		QString initiator() const;
++		
++		/*
++		 * Start negotiation.
++		 * This function is called after receiving a session initiate.
++		 * This will start negotiating a connection depending on the transport.
++		 */
++		void startNegotiation();
++		
++		/*
++		 * Returns a pointer to the first JingleContent with the name n.
++		 * Each content must have a unique name so returning the first
++		 * one returns the only one.
++		 */
++		JingleContent *contentWithName(const QString& n);
++		
++		/*
++		 * Returns the sid of this session.
++		 */
++		QString sid() const;
++
++		/*
++		 * Call this function when a session-accept jingle action has been received for it.
++		 * Once the session is accepted, we will get the supported payloads of the initiator
++		 * and switch to Active state, Media can begin to flow on each content's socket.
++		 */
++		void sessionAccepted(const QDomElement&);
++
++		// Jingle actions
++		enum JingleAction {
++			SessionInitiate = 0,
++			SessionTerminate,
++			SessionAccept,
++			SessionInfo,
++			ContentAdd,
++			ContentRemove,
++			ContentModify,
++			TransportReplace,
++			TransportAccept,
++			TransportInfo,
++			NoAction
++		};
++		
++		// Session states
++		enum State {
++			Pending = 0,
++			Active,
++			Ended
++		};
++		
++		/*
++		 * Returns the current state of the session.
++		 */
++		State state() const;
++
++	signals:
++		
++		/*
++		 * Emitted once a session-terminate has been acknowledged
++		 */
++		void terminated();
++		
++		/* 
++		 * needData() is emitted once for each content.
++		 * Once it has been emitted, streaming must start on this socket until stopSending is emitted.
++		 * FIXME: Shouldn't pass by here, should stay in JingleContent.
++		 */
++		void needData(XMPP::JingleContent*);
++
++		/**
++		 * Emitted when the session state has changed (Pending --> Active)
++		 */
++		void stateChanged();
++	public slots:
++		
++		/*
++		 * This slot is called when a content-remove has been acked.
++		 */
++		void slotRemoveAcked();
++		
++		/*
++		 * This slot is called when a session-terminate has been acked.
++		 */
++		void slotSessTerminated();
++
++		/*
++		 * This slot is called when data is received on the raw udp socket.
++		 */
++		void slotRawUdpDataReady();
++
++		/*
++		 * Called when a content has been established.
++		 */
++		void slotContentConnected();
++
++		/*
++		 * This slot is called when a JT_JingleAction has been acknowledged
++		 * and we just have to delete it.
++		 */
++		void slotAcked();
++
++		/*
++		 * This slot is called when the session has been accepted by the responder.
++		 */
++		void slotSessionAcceptAcked();
++
++		/*
++		 * This slot is called when a "receive" informational message has been received.
++		 * Currently, this slot simply calls setSending() on all contents.
++		 */
++		void slotReceivingData();
++
++	private:
++		class Private;
++		Private *d;
++		
++		/*
++		 * Sends ice udp cadidates
++		 */
++		void sendIceUdpCandidates();
++		
++		/*
++		 * Starts a raw udp connection for this JingleContent.
++		 * (Create socket, ask to start sending data on it)
++		 */
++		void startRawUdpConnection(JingleContent*);
++		
++		/*
++		 * Deletes an action when it is not used anymore.
++		 */
++		void deleteAction(JT_JingleAction*);
++	};
++}
++
++#endif
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglesessionmanager.cpp iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesessionmanager.cpp
+--- iris-1.0.0/src/xmpp/jingle/jinglesessionmanager.cpp	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesessionmanager.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,389 @@
++/*
++ * jinglesessionmanager.cpp - Manager for Jingle sessions
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#include "jinglesessionmanager.h"
++#include "jingletasks.h"
++
++#include <QHttp>
++
++using namespace XMPP;
++
++class JingleSessionManager::Private
++{
++public:
++	JT_PushJingleAction *pjs;
++	Client *client;
++	QList<JingleSession*> sessions;
++	QStringList supportedTransports;
++	QList<QDomElement> supportedAudioPayloads;
++	QList<QDomElement> supportedVideoPayloads;
++	QStringList supportedProfiles;
++	QList<int> usedPorts;
++	int firstPort;
++	QString ip;
++	QHttp *http;
++};
++
++JingleSessionManager::JingleSessionManager(Client* c)
++: d(new Private)
++{
++	qDebug() << "JingleSessionManager::JingleSessionManager created.";
++	d->client = c;
++	d->pjs = new JT_PushJingleAction(d->client->rootTask());
++	connect(d->pjs, SIGNAL(newSessionIncoming()),
++		this, SLOT(slotSessionIncoming()));
++	connect(d->pjs, SIGNAL(removeContent(const QString&, const QStringList&)),
++		this, SLOT(slotRemoveContent(const QString&, const QStringList&)));
++	connect(d->pjs, SIGNAL(sessionInfo(const QDomElement&)),
++		this, SLOT(slotSessionInfo(const QDomElement&)));
++	connect(d->pjs, SIGNAL(transportInfo(const QDomElement&)),
++		this, SLOT(slotTransportInfo(const QDomElement&)));
++	connect(d->pjs, SIGNAL(sessionTerminate(const QString&, const JingleReason&)),
++		this, SLOT(slotSessionTerminate(const QString&, const JingleReason&)));
++	connect(d->pjs, SIGNAL(sessionAccepted(const QDomElement&)),
++		this, SLOT(slotSessionAccepted(const QDomElement&)));
++
++	Features f = d->client->features();
++	
++	f.addFeature(NS_JINGLE);
++//	f.addFeature(NS_JINGLE_TRANSPORTS_ICE);
++	f.addFeature(NS_JINGLE_TRANSPORTS_RAW);
++	f.addFeature(NS_JINGLE_APPS_RTP);
++//	f.addFeature("urn:xmpp:tmp:jingle:apps:video-rtp");
++
++	d->client->setFeatures(f);
++
++	d->firstPort = 9000;
++	
++	//Get External IP address, This is not Standard and might not work but let's try it before we have ICE support
++	//whatismyip.org has a better interface for this
++	//d->http = new QHttp(this);
++	//d->http->setHost("www.swlink.net");
++	//connect(d->http, SIGNAL(done(bool)), this, SLOT(slotExternalIPDone(bool)));
++	//d->http->get("/~styma/REMOTE_ADDR.shtml");
++}
++
++void JingleSessionManager::slotExternalIPDone(bool err)
++{
++	d->ip = "";
++	if (err)
++	{
++		qDebug() << "err =" << err;
++		d->http->deleteLater(); //FIXME:Not Sure about that
++		return;
++	}
++		
++	QByteArray pageData = d->http->readAll();
++	d->ip = pageData.split('\n').at(4);
++	qDebug() << "Received External IP :" << d->ip;
++
++	QDomDocument *xmlPage = new QDomDocument();
++	QString errMess;
++	int line, col;
++	if (xmlPage->setContent(pageData, false, &errMess, &line, &col))
++	{
++		qDebug() << "Parsing Ok";
++		/*d->ip= "";*/
++	}
++	else
++	{
++		qDebug() << " JingleSessionManager::slotExternalIPDone : Unable to parse HTML document." << errMess << line << col;
++	}
++	
++	delete d->http;
++}
++
++void JingleSessionManager::setExternalIP(const QString& eip)
++{
++	d->ip = eip;
++}
++
++QString JingleSessionManager::externalIP() const
++{
++	return d->ip;
++}
++
++JingleSessionManager::~JingleSessionManager()
++{
++	delete d;
++}
++
++void JingleSessionManager::setSupportedTransports(const QStringList& transports)
++{
++	d->supportedTransports = transports;
++}
++
++void JingleSessionManager::setSupportedAudioPayloads(const QList<QDomElement>& payloads)
++{
++	d->supportedAudioPayloads = payloads;
++}
++
++QList<QDomElement> JingleSessionManager::supportedAudioPayloads() const
++{
++	return d->supportedAudioPayloads;
++}
++
++void JingleSessionManager::setSupportedVideoPayloads(const QList<QDomElement>& payloads)
++{
++	d->supportedVideoPayloads = payloads;
++}
++
++QList<QDomElement> JingleSessionManager::supportedVideoPayloads() const
++{
++	return d->supportedVideoPayloads;
++}
++
++void JingleSessionManager::setSupportedProfiles(const QStringList& profiles)
++{
++	d->supportedProfiles = profiles;
++}
++
++JingleSession *JingleSessionManager::startNewSession(const Jid& toJid, const QList<JingleContent*>& contents)
++{
++	XMPP::JingleSession *session = new XMPP::JingleSession(d->client->rootTask(), toJid.full());
++	session->setInitiator(d->client->jid().full());
++	session->addContents(contents);
++	d->sessions << session;
++	connect(session, SIGNAL(terminated()), this, SLOT(slotSessionTerminated()));
++	//connect(others);
++	session->start();
++	return session;
++}
++
++void JingleSessionManager::slotSessionTerminated()
++{
++	JingleSession* sess = static_cast<JingleSession*>(sender());
++
++	for (int i = 0; i < d->sessions.count(); i++)
++	{
++		if (d->sessions[i] == sess)
++			d->sessions.removeAt(i);
++	}
++}
++
++void JingleSessionManager::slotSessionIncoming()
++{
++	qDebug() << "JingleSessionManager::slotSessionIncoming() called.";
++	
++	JingleSession *sess = d->pjs->takeNextIncomingSession();
++	d->sessions << sess;
++	connect(sess, SIGNAL(terminated()), this, SLOT(slotSessionTerminated()));
++	//QList<QString> incompatibleContents;
++	
++	QList<QString> unsupportedPayloads;
++	// This is a list of the names of the contents which have no supported payloads.
++	
++	QList<QString> unsupportedTransports;
++	// This is a list of the names of the contents which have no supported transports
++	// We have to remove all contents present in those lists.
++	//
++	// If no content is supported, reject the session because it's not possible to establish a session.
++
++	for (int i = 0; i < sess->contents().count(); i++)
++	{
++		JingleContent *c = sess->contents()[i];
++		
++		//Set supported payloads for this content.
++		c->setPayloadTypes(c->type() == JingleContent::Audio ? d->supportedAudioPayloads : d->supportedVideoPayloads);
++
++		// Check payloads for the content c
++		if (!checkSupportedPayloads(c))
++		{
++			//incompatibleContents << c->name();
++			unsupportedPayloads << c->name();
++			continue;
++		}
++		
++		if (!checkSupportedTransport(c))
++		{
++			//incompatibleContents << c->name();
++			unsupportedTransports << c->name();
++		}
++	}
++	
++	if (unsupportedPayloads.count() + unsupportedTransports.count() == sess->contents().count())
++	{
++		//Reject the session.
++		JingleReason r(JingleReason::UnsupportedApplications);
++		sess->sessionTerminate(r);
++		//What happens when we receive the ack of the session-terminate ?
++		return;
++	}
++	else if (unsupportedPayloads.count() + unsupportedTransports.count() > 0)
++	{
++		//remove this contents list
++		sess->removeContent(unsupportedPayloads + unsupportedTransports);
++		return;
++	}
++	
++	emit newJingleSession(sess);
++	
++	d->sessions.last()->ring();
++	
++	d->sessions.last()->startNegotiation();
++}
++
++bool JingleSessionManager::checkSupportedPayloads(JingleContent *c)
++{
++	qDebug() << "We have" << c->responderPayloads().count() << "responder payloads in this content.";
++	for (int i = 0; i < c->payloadTypes().count(); i++)
++	{
++		qDebug() << "We have" << d->supportedAudioPayloads.count() << "supported payloads.";
++		for (int j = 0; j < d->supportedAudioPayloads.count(); j++)
++		{
++			qDebug() << "compare" << c->payloadTypes().at(i).attribute("name") << "to" << d->supportedAudioPayloads.at(j).attribute("name");
++			if (c->payloadTypes().at(i).attribute("name") == d->supportedAudioPayloads.at(j).attribute("name"))
++			{
++				//This payload name is supported.
++				//A static method should be written to compare 2 payloads elements.
++				qDebug() << "return true";
++				return true;
++			}
++		}
++	}
++
++	qDebug() << "return false";
++	return false;
++}
++
++bool JingleSessionManager::checkSupportedTransport(JingleContent *c)
++{
++	/*for (int i = 0; i < d->supportedTransports.count(); i++)
++	{
++		qDebug() << "compare" << c->transport().attribute("xmlns") << "to" << d->supportedTransports.at(i);
++		if (c->transport().attribute("xmlns") == d->supportedTransports.at(i))
++		{
++			qDebug() << "return true";
++			return true;
++		}
++	}
++	qDebug() << "return false";*/
++
++	return true;
++}
++
++//void JingleSessionManager::removeContent(const QString& sid, const QString& cName)
++//{
++//	for (int i = 0; i < )
++//}
++
++void JingleSessionManager::slotRemoveContent(const QString& sid, const QStringList& cNames)
++{
++	qDebug() << "JingleSessionManager::slotRemoveContent(" << sid << ", " << cNames << ") called.";
++	//emit contentRemove(sid, cNames); //The slotRemoveContent slot should not exist so we can connect both signals directly.
++	/*
++	 * Whatever we have to do at this point will be done by the application on the JingleSession.
++	 * That means that the application must keep a list of the JingleSession or this class should
++	 * give access to the session list.
++	 */
++}
++
++JingleSession *JingleSessionManager::session(const QString& sid)
++{
++	JingleSession *sess;
++	sess = 0;
++	for (int i = 0; i < d->sessions.count(); i++)
++	{
++		if (d->sessions.at(i)->sid() == sid)
++		{
++			sess = d->sessions.at(i);
++			break;
++		}
++	}
++	return sess;
++}
++
++void JingleSessionManager::slotSessionInfo(const QDomElement& x)
++{
++	JingleSession *sess = session(x.attribute("sid"));
++	if (sess == 0)
++	{
++		//unknownSession();
++		return;
++	}
++	sess->addSessionInfo(x.firstChildElement());
++}
++
++void JingleSessionManager::slotTransportInfo(const QDomElement& x)
++{
++	JingleSession *sess = session(x.attribute("sid"));
++	if (sess == 0)
++	{
++		qDebug() << "Session is null, We have a proble here...";
++		//unknownSession();
++		return;
++	}
++	//sess->contentWithName(x.firstChildElement().attribute("name"))->addTransportInfo(x.firstChildElement().firstChildElement());
++	sess->addTransportInfo(x.firstChildElement());
++}
++
++void JingleSessionManager::slotSessionTerminate(const QString& sid, const JingleReason& reason)
++{
++	Q_UNUSED(reason)
++	JingleSession *sess = session(sid);
++	if (!sess)
++	{
++		//sendUnknownSession([need the stanza id]);
++		return;
++	}
++
++	//Remove the session from the sessions list (the session is not destroyed, it has to be done by the application.)
++	for (int i = 0; i < d->sessions.count(); i++)
++	{
++		if (sess == d->sessions[i])
++		{
++			d->sessions.removeAt(i);
++			break;
++		}
++	}
++	emit sessionTerminate(sess);
++	
++}
++
++int JingleSessionManager::nextRawUdpPort()
++{
++	int lastUsed;
++	if (d->usedPorts.count() == 0)
++		lastUsed = d->firstPort - 1;
++	else
++		lastUsed = d->usedPorts.last();
++	d->usedPorts << lastUsed + 1 << lastUsed + 2;
++	qDebug() << "JingleSessionManager::nextRawUdpPort() returns" << (lastUsed + 1);
++	return (lastUsed + 1);
++}
++
++void JingleSessionManager::setFirstPort(int f)
++{
++	d->firstPort = f;
++}
++
++void JingleSessionManager::slotSessionAccepted(const QDomElement& x)
++{
++	JingleSession *sess = session(x.attribute("sid"));
++	if (sess == 0)
++	{
++		qDebug() << "Session is null, We have a proble here...";
++		//unknownSession();
++		return;
++	}
++	
++	qDebug() << "JingleSessionManager::slotSessionAccept(const QDomElement& x) : call sess->sessionAccepted(x);";
++	sess->sessionAccepted(x);
++}
+diff -Nur iris-1.0.0/src/xmpp/jingle/jinglesessionmanager.h iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesessionmanager.h
+--- iris-1.0.0/src/xmpp/jingle/jinglesessionmanager.h	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jinglesessionmanager.h	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,158 @@
++/*
++ * jinglesessionmanager.cpp - Manager for Jingle sessions
++ *
++ * Manages all Jingle sessions.
++ * This class receives all incoming jingle actions and perform these
++ * actions on the right jingle session.
++ * It also keeps information about protocols supported by the application (transports, payloads, profiles)
++ *
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++#ifndef JINGLE_SESSION_MANAGER
++#define JINGLE_SESSION_MANAGER
++
++//#include <QObject>
++
++#include "im.h"
++//#include "xmpp_client.h"
++//#include "xmpp_jid.h"
++
++namespace XMPP
++{
++	class JingleSession;
++	class JingleContent;
++	class JingleReason;
++	class JingleSessionManager : public QObject
++	{
++		Q_OBJECT
++	public:
++		JingleSessionManager(Client*);
++		~JingleSessionManager();
++		
++		/*
++		 * Create a new jingle session to a Jid and with a list of contents,
++		 * starts it and returns it.
++		 */
++		XMPP::JingleSession *startNewSession(const Jid&, const QList<JingleContent*>&);
++		
++		/*
++		 * Set supported transports for jingle sessions.
++		 */
++		void setSupportedTransports(const QStringList&);
++		
++		/*
++		 * Set supported audio payloads for jingle sessions.
++		 */
++		void setSupportedAudioPayloads(const QList<QDomElement>&);
++
++		/*
++		 * Returns the supported audio payloads.
++		 */
++		QList<QDomElement> supportedAudioPayloads() const;
++		
++		/*
++		 * Set supported video payloads for jingle sessions.
++		 */
++		void setSupportedVideoPayloads(const QList<QDomElement>&); // FIXME:a class name QNodeList does exists in Qt.
++
++		/*
++		 * Returns the supported video payloads.
++		 */
++		QList<QDomElement> supportedVideoPayloads() const;
++		
++		/*
++		 * Set supported profiles for jingle sessions.
++		 */
++		void setSupportedProfiles(const QStringList&);
++
++		/*
++		 * Provides the next usable port for a raw-udp session.
++		 * As the application should create a rtcp port with the
++		 * provided rtp socket port + 1, this method will always
++		 * give a port incremented by 2.
++		 * The first port will be 9000 by default but it can be modified
++		 * with setFirstPort().
++		 * Also, this method will share a list of used ports with the
++		 * iceUdpPort method.
++		 * It would be nice to be informed of the ports which are freed
++		 * when a session is terminated so we can reuse them.
++		 */
++		int nextRawUdpPort();
++		void setFirstPort(int);
++
++		QString externalIP() const;
++		void setExternalIP(const QString& eip);
++	signals:
++		
++		/*
++		 * Emitted when a new jingle session comes.
++		 */
++		void newJingleSession(XMPP::JingleSession*);
++
++		/*
++		 * Emitted when a session-terminate is received.
++		 */
++		void sessionTerminate(XMPP::JingleSession*);
++	
++	public slots:
++		/* 
++		 * Slots for each jingle action
++		 */
++		void slotSessionIncoming();
++		void slotRemoveContent(const QString&, const QStringList&);
++		void slotSessionInfo(const QDomElement&);
++		void slotTransportInfo(const QDomElement&);
++		void slotSessionTerminate(const QString&, const JingleReason&);
++		void slotSessionAccepted(const QDomElement&);
++
++		/*
++		 * This slot is called when a session has been
++		 * terminated and should be removed from the
++		 * sessions list.
++		 */
++		void slotSessionTerminated();
++
++		/*
++		 * This slot is called when the external IP has been retrieved by http
++		 */
++		void slotExternalIPDone(bool);
++
++	private:
++		class Private;
++		Private *d;
++		/*
++		 * Returns the session with the SID sid.
++		 */
++		JingleSession *session(const QString& sid);
++
++		/*
++		 * Check if this content has supported contents.
++		 * If yes, returns true, returns false if not.
++		 */
++		bool checkSupportedPayloads(JingleContent *c);
++		
++		/*
++		 * Check if this content has a supported transport.
++		 * If yes, returns true, returns false if not.
++		 */
++		bool checkSupportedTransport(JingleContent *c);
++
++	};
++}
++
++#endif
+diff -Nur iris-1.0.0/src/xmpp/jingle/jingletasks.cpp iris-1.0.0-023_jingle/src/xmpp/jingle/jingletasks.cpp
+--- iris-1.0.0/src/xmpp/jingle/jingletasks.cpp	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jingletasks.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,687 @@
++/*
++ * jingletasks.cpp - Tasks for the Jingle specification.
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#include <QtDebug>
++#include <QNetworkInterface>
++#include <QUdpSocket>
++#include <stdio.h>
++
++#include "jinglesessionmanager.h"
++
++#include "jingletasks.h"
++#include "protocol.h"
++#include "xmpp_xmlcommon.h"
++
++using namespace XMPP;
++
++JingleSession::JingleAction jingleAction(const QDomElement& x)
++{
++	QString action = x.firstChildElement().attribute("action");
++	if (action == "session-initiate")
++		return JingleSession::SessionInitiate;
++	else if (action == "session-terminate")
++		return JingleSession::SessionTerminate;
++	else if (action == "session-accept")
++		return JingleSession::SessionAccept;
++	else if (action == "session-info")
++		return JingleSession::SessionInfo;
++	else if (action == "content-add")
++		return JingleSession::ContentAdd;
++	else if (action == "content-remove")
++		return JingleSession::ContentRemove;
++	else if (action == "content-modify")
++		return JingleSession::ContentModify;
++	else if (action == "transport-replace")
++		return JingleSession::TransportReplace;
++	else if (action == "transport-accept")
++		return JingleSession::TransportAccept;
++	else if (action == "transport-info")
++		return JingleSession::TransportInfo;
++	else
++		return JingleSession::NoAction;
++}
++
++
++
++//------------------------
++// JT_PushJingleAction
++//------------------------
++//RECEIVES THE ACTIONS
++
++static JingleReason::Type stringToType(const QString& str)
++{
++	if (str == "busy")
++	{
++		return JingleReason::Busy;
++	}
++	else if (str == "decline")
++	{
++		return JingleReason::Decline;
++	}
++	else
++	{
++		return JingleReason::NoReason;
++	}
++
++}
++
++class JT_PushJingleAction::Private
++{
++public:
++	JingleSession *incomingSession;
++	QList<JingleSession*> incomingSessions;
++	QDomElement iq;
++	QString id;
++	Jid from;
++};
++
++JT_PushJingleAction::JT_PushJingleAction(Task *parent)
++: Task(parent), d(new Private)
++{
++	qDebug() << "Creating the PushJingleSession task....";
++}
++
++JT_PushJingleAction::~JT_PushJingleAction()
++{
++	qDebug() << "Deleting the PushJingleSession task....";
++	delete d;
++}
++
++void JT_PushJingleAction::onGo()
++{
++//	send(d->iq);
++}
++
++bool JT_PushJingleAction::take(const QDomElement &x)
++{
++	/*
++	 * We take this stanza when it is a session-initiate stanza for sure.
++	 * Now, 2 possibilities :
++	 * 	* This task is used by the JingleSession to established the connection
++	 * 	* A new JT_JingleSession is used by the JingleSession to established the connection
++	 * I'd rather use the second one, see later...
++	 */
++	if (x.firstChildElement().tagName() != "jingle")
++		return false;
++	
++	if (x.attribute("type") == "error")
++	{
++		jingleError(x);
++		return true;
++	}
++
++	QStringList cName;
++	QString sid = x.firstChildElement().attribute("sid");
++	d->from = Jid(x.attribute("from"));
++	QDomElement jingle;
++	QDomElement content;
++	QDomElement reason, e;
++	QString condition;
++	QString text;
++	switch(jingleAction(x))
++	{
++	case JingleSession::SessionInitiate :
++		qDebug() << "New Incoming session : " << sid;
++		d->id = x.attribute("id");
++		ack();
++
++		//Prepare the JingleSession instance.
++		d->incomingSession = new JingleSession(parent(), Jid());
++		d->incomingSession->setTo(x.attribute("from"));
++		jingle = x.firstChildElement();
++		d->incomingSession->setInitiator(jingle.attribute("initiator"));
++		d->incomingSession->setSid(jingle.attribute("sid"));
++		content = jingle.firstChildElement();
++		while (!content.isNull())
++		{
++			if (content.tagName() == "content")
++				d->incomingSession->addContent(content);
++			content = content.nextSiblingElement();
++		}
++
++		d->incomingSessions << d->incomingSession;
++
++		emit newSessionIncoming();
++		 /* TODO : 
++		  * 	Continue to negotiate the contents to use --> Done by the JingleSession.
++		  */
++		break;
++	case JingleSession::ContentRemove : 
++		qDebug() << "Content remove for session " << sid;
++		// Ack content-remove
++		d->id = x.attribute("id");
++		ack();
++		
++		content = x.firstChildElement().firstChildElement();
++		while (!content.isNull())
++		{
++			cName << content.attribute("name");
++			qDebug() << " * Remove : " << cName;
++			content = content.nextSiblingElement();
++		}
++		emit removeContent(sid, cName);
++		/*if (d->state == WaitContentAccept)
++		{
++			d->state = StartNegotiation;
++			 *
++			 * Content has been removed, we can take it as a content-accept.
++			 * Now, we stop ringing but the session should change it by itself depending
++			 * on the state when receiving a content-remove
++			 * After we acknowledge the responder that the content has been removed,
++			 * we must start negotiate a candidate with him (depending if we use ICE-UDP or RAW-UDP)
++			 * ADVICE: Begin with RAW-UDP, it is simpler.
++			 *
++		}*/
++		break;
++	case JingleSession::SessionInfo :
++		qDebug() << "Session Info for session " << sid;
++		// Ack session-info
++		d->id = x.attribute("id");
++		ack();
++		
++		emit sessionInfo(x.firstChildElement());
++		break;
++	case JingleSession::TransportInfo :
++		qDebug() << "Transport Info for session " << sid;
++		d->id = x.attribute("id");
++		ack();
++		
++		emit transportInfo(x.firstChildElement());
++
++		break;
++	case JingleSession::SessionTerminate :
++		qDebug() << "Transport Info for session " << sid;
++		d->id = x.attribute("id");
++		ack();
++		
++		reason = x.firstChildElement().firstChildElement();
++		e = reason.firstChildElement();
++		while(!e.isNull())
++		{
++			if (e.tagName() == "condition")
++				condition = e.firstChildElement().tagName();
++			else if (e.tagName() == "text")
++				text = e.firstChildElement().toText().data();
++
++			e = e.nextSiblingElement();
++		}
++		
++		emit sessionTerminate(sid, JingleReason(stringToType(condition), text));
++
++		break;
++	case JingleSession::SessionAccept :
++		qDebug() << "Transport Info for session " << sid;
++		d->id = x.attribute("id");
++		ack();
++
++		emit sessionAccepted(x.firstChildElement());
++		break;
++	default:
++		qDebug() << "There are some troubles with the Jingle Implementation. Be carefull that this is still low performances software.";
++	}
++	return true;
++}
++
++JingleSession *JT_PushJingleAction::takeNextIncomingSession()
++{
++	return d->incomingSessions.takeLast();
++}
++
++void JT_PushJingleAction::ack()
++{
++	d->iq = createIQ(doc(), "result", d->from.full(), d->id);
++	send(d->iq);
++}
++
++void JT_PushJingleAction::jingleError(const QDomElement& x)
++{
++	qDebug() << "There was an error from the responder. Not supported yet.";
++	Q_UNUSED(x)
++	//emit error(???);
++}
++
++//-----------------------
++// JT_JingleAction
++//-----------------------
++
++class JT_JingleAction::Private
++{
++public :
++	JingleSession *session;
++	QDomElement iq;
++	QString sid;
++	Jid to;
++};
++
++JT_JingleAction::JT_JingleAction(Task *parent)
++: Task(parent), d(new Private())
++{
++	qDebug() << "Creating JT_JingleAction";
++	d->session = 0;
++}
++
++JT_JingleAction::~JT_JingleAction()
++{
++	delete d;
++}
++
++void JT_JingleAction::setSession(JingleSession *sess)
++{
++	d->session = sess;
++}
++
++bool interfaceOrder(const QHostAddress& a1, const QHostAddress& a2)
++{
++	Q_UNUSED(a2)
++	if ((a1 != QHostAddress::LocalHost) && (a1 != QHostAddress::Null) && (a1.protocol() != QAbstractSocket::IPv6Protocol))
++		return true;
++	return false;
++}
++
++void JT_JingleAction::initiate()
++{
++	qDebug() << id();
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-initiate");
++	jingle.setAttribute("initiator", client()->jid().full());
++	jingle.setAttribute("sid", d->session->sid());
++
++	QString eip = client()->jingleSessionManager()->externalIP();
++
++	for (int i = 0; i < d->session->contents().count(); i++)
++	{
++		QDomElement transport = d->session->contents()[i]->transport();
++		//qDebug() << "Transport from the JingleContent is : " << client()->stream().xmlToString(transport, false);
++		if (transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++		{
++			qDebug() << "Set raw-udp candidate for content" << i;
++			QDomElement candidate = doc()->createElement("candidate");
++			QString ip;
++
++			//Trying to get the address with the most chances to succeed.
++			if (eip != "") //does not seem to work...
++			{
++				ip = eip;
++			}
++			else
++			{
++				QNetworkInterface *interface = new QNetworkInterface();
++				QList<QHostAddress> ips = interface->allAddresses();
++				qSort(ips.begin(), ips.end(), interfaceOrder);
++	
++				if (ips.count() == 0)
++				{
++					qDebug() << "No Internet address found. Are you connected ?";
++					//emit error(NoNetwork);
++					return;
++				}
++				ip = ips[0].toString();
++			}
++			candidate.setAttribute("ip", ip); // ips[0] is not 127.0.0.1 if there is other adresses.
++			int port = client()->jingleSessionManager()->nextRawUdpPort();
++			//qDebug() << "Port =" << port;
++			//qDebug() << "Port =" << QString("%1").arg(port);
++			candidate.setAttribute("port", QString("%1").arg(port));
++			candidate.setAttribute("generation", "0"); // FIXME:I don't know yet what it is.
++			transport.appendChild(candidate);
++			d->session->contents()[i]->bind(QHostAddress(ip), port);
++			//qDebug() << client()->stream().xmlToString(transport, false);
++		}
++		else if (transport.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++		{
++			//TODO:implement me.
++		}
++		//d->session->contents()[i]->setTransport(transport);
++		jingle.appendChild(d->session->contents()[i]->contentElement());
++	}
++
++	d->iq.appendChild(jingle);
++	//send(d->iq);
++}
++
++
++void JT_JingleAction::contentAccept()
++{
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++
++	qDebug() << "Sending the content-accept to : " << d->session->to().full();
++	
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++	
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "content-accept");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++
++	d->iq.appendChild(jingle);
++	//send(d->iq);
++}
++
++void JT_JingleAction::ringing()
++{
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++
++	qDebug() << "Sending the session-info (ringing) to : " << d->session->to().full();
++	
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++	
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-info");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	
++	QDomElement ring = doc()->createElement("ringing");
++	ring.setAttribute("xmlns", "urn:xmpp:tmp:jingle:apps:audio-rtp:info");
++
++	jingle.appendChild(ring);
++	d->iq.appendChild(jingle);
++
++	//send(d->iq);
++}
++
++void JT_JingleAction::terminate(const JingleReason& r)
++{
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the session-terminate to : " << d->session->to().full();
++	
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++	
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-terminate");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++
++	QDomElement reason = doc()->createElement("reason");
++	QDomElement condition = doc()->createElement("condition");
++
++	QDomElement rReason;
++	switch(r.type())
++	{
++	case JingleReason::Decline :
++		rReason = doc()->createElement("decline");
++		break;
++	case JingleReason::NoReason :
++		rReason = doc()->createElement("no-error");
++		break;
++	case JingleReason::UnsupportedApplications :
++		rReason = doc()->createElement("unsupported-applications");
++		break;
++	default:
++		rReason = doc()->createElement("unknown");
++	}
++
++	d->iq.appendChild(jingle);
++	jingle.appendChild(reason);
++	reason.appendChild(condition);
++	condition.appendChild(rReason);
++	//send(d->iq);
++}
++
++void JT_JingleAction::removeContents(const QStringList& c)
++{
++	// ----------------------------
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the session-terminate to : " << d->session->to().full();
++	
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++	
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "content-remove");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	//---------This par should be in another method (createJingleIQ(...))
++	
++	for (int i = 0; i < c.count(); i++)
++	{
++		QDomElement content = doc()->createElement("content");
++		content.setAttribute("name", c[i]);
++		jingle.appendChild(content);
++	}
++	//FIXME:MUST the 'creator' tag be there ?
++	
++	d->iq.appendChild(jingle);
++
++	//send(d->iq);
++}
++
++void JT_JingleAction::transportInfo(JingleContent *c)
++{
++	QDomElement e = c->transport();
++	// ----------------------------
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the transport-info to : " << d->session->to().full();
++
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "transport-info");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	//---------This part should be in another method (createJingleIQ(...))
++	QString eip = client()->jingleSessionManager()->externalIP();
++
++	if (e.attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++	{
++		QDomElement content = doc()->createElement("content");
++		content.setAttribute("name", c->name());
++		content.setAttribute("creator", d->session->initiator() == d->session->to().full() ? d->session->to().full() : "initiator");
++
++		QDomElement transport = doc()->createElement("transport");
++		transport.setAttribute("xmlns", NS_JINGLE_TRANSPORTS_RAW);
++		
++		QDomElement candidate = doc()->createElement("candidate");
++		QString ip;
++
++		//Trying to get the address with the most chances to succeed.
++		if (eip != "") //does not seem to work.
++		{
++			ip = eip;
++		}
++		else
++		{
++			QNetworkInterface *interface = new QNetworkInterface();
++			QList<QHostAddress> ips = interface->allAddresses();
++			qSort(ips.begin(), ips.end(), interfaceOrder);
++
++			if (ips.count() == 0)
++			{
++				qDebug() << "No Internet address found. Are you connected ?";
++				//emit error(NoNetwork);
++				return;
++			}
++			ip = ips[0].toString();
++		}
++		candidate.setAttribute("ip", ip); // ips[0] is not 127.0.0.1 if there is other adresses.
++		int port = client()->jingleSessionManager()->nextRawUdpPort();
++		//qDebug() << "Port =" << port;
++		//qDebug() << "Port =" << QString("%1").arg(port);
++		candidate.setAttribute("port", QString("%1").arg(port));
++		candidate.setAttribute("generation", "0"); // FIXME:I don't know yet what it is.
++		transport.appendChild(candidate);
++		content.appendChild(transport);
++		jingle.appendChild(content);
++		d->iq.appendChild(jingle);
++		
++		c->bind(QHostAddress(ip), port);
++	}
++	else if (e.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++	{
++		qDebug() << "ICE-UDP is not implemented yet.";
++	}
++	else
++	{
++		qDebug() << "Unsupported protocol (" << e.attribute("xmlns") << ")";
++		return;
++	}
++
++	//send(d->iq);
++}
++
++void JT_JingleAction::trying(const JingleContent& c)
++{
++	QDomElement e = c.transport();
++	// ----------------------------
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the session-info to : " << d->session->to().full();
++
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-info");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	//---------This par should be in another method (createJingleIQ(...))
++	if (e.attribute("xmlns") == NS_JINGLE_TRANSPORTS_RAW)
++	{
++		QDomElement trying = doc()->createElement("trying");
++		trying.setAttribute("xmlns", "urn:xmpp:tmp:jingle:transports:raw-udp:info");
++		jingle.appendChild(trying);
++		d->iq.appendChild(jingle);
++	}
++	else if (e.attribute("xmlns") == NS_JINGLE_TRANSPORTS_ICE)
++	{
++		qDebug() << "ICE-UDP is not implemented yet. (is trying message used with ICE-UDP ??? )";
++	}
++	else
++	{
++		qDebug() << "Unsupported protocol (" << e.attribute("xmlns") << ")";
++		return;
++	}
++
++	//send(d->iq);
++	
++}
++
++void JT_JingleAction::received()
++{
++	// ----------------------------
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the session-info to : " << d->session->to().full();
++
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-info");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	//---------This par should be in another method (createJingleIQ(...))
++	QDomElement received = doc()->createElement("received");
++	
++	//That depends of the session content's transport.
++	//Ice-udp does not need the "receive" informationnal message.
++	received.setAttribute("xmlns", "urn:xmpp:tmp:jingle:transports:raw-udp:info");
++	
++	jingle.appendChild(received);
++	d->iq.appendChild(jingle);
++}
++
++void JT_JingleAction::sessionAccept(const QList<JingleContent*>& contents)
++{
++	// ----------------------------
++	if (d->session == 0)
++	{
++		qDebug() << "d->session is NULL, did you set it calling JT_JingleAction::setSession() ?";
++		return;
++	}
++	qDebug() << "Sending the session-accept to : " << d->session->to().full();
++
++	d->iq = createIQ(doc(), "set", d->session->to().full(), id());
++	d->iq.setAttribute("from", client()->jid().full());
++
++	QDomElement jingle = doc()->createElement("jingle");
++	jingle.setAttribute("xmlns", NS_JINGLE);
++	jingle.setAttribute("action", "session-accept");
++	jingle.setAttribute("initiator", d->session->initiator());
++	jingle.setAttribute("sid", d->session->sid());
++	//---------This par should be in another method (createJingleIQ(...))
++	
++	for (int i = 0; i < contents.count(); i++)
++	{
++		jingle.appendChild(contents[i]->contentElement());
++	}
++
++	d->iq.appendChild(jingle);
++	qDebug() << "Prepare to send :";
++	client()->stream().xmlToString(d->iq, false);
++
++	//send(d->iq);
++}
++
++bool JT_JingleAction::take(const QDomElement &x)
++{
++	if (!iqVerify(x, d->session->to().full(), id()))
++		return false;
++	
++	setSuccess();
++	emit finished();
++
++	return true;
++}
++
++void JT_JingleAction::onGo()
++{
++	send(d->iq);
++}
++
+diff -Nur iris-1.0.0/src/xmpp/jingle/jingletasks.h iris-1.0.0-023_jingle/src/xmpp/jingle/jingletasks.h
+--- iris-1.0.0/src/xmpp/jingle/jingletasks.h	1970-01-01 01:00:00.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/jingle/jingletasks.h	2013-02-13 19:48:35.000000000 +0100
+@@ -0,0 +1,221 @@
++/*
++ * jingletasks.cpp - Tasks for the Jingle specification.
++ * Copyright (C) 2008 - Detlev Casanova <detlev.casanova at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++#ifndef JINGLE_TASKS
++#define JINGLE_TASKS
++
++#include <QDomElement>
++#include <QUdpSocket>
++
++#include "im.h"
++#include "xmpp_task.h"
++#include "jinglesession.h"
++#include "jinglecontent.h"
++
++namespace XMPP
++{
++	class JingleSession;
++	class JingleReason;
++	
++	/*
++	 * This class is a Task that received all jingle actions and give them to the JingleSessionManager
++	 */
++	class IRIS_EXPORT JT_PushJingleAction : public Task
++	{
++		Q_OBJECT
++	public:
++		JT_PushJingleAction(Task*);
++		~JT_PushJingleAction();
++
++		void onGo();
++		bool take(const QDomElement&);
++		
++		/*
++		 * Returns the next incoming session, this
++		 * method should be called each time the newSessionIncoming()
++		 * SIGNAL is emitted.
++		 */
++		JingleSession *takeNextIncomingSession();
++	signals:
++		/*
++		 * Emitted when a new session is incoming. the JingleSession
++		 * can be retrieved with takeNextIncomingSession()
++		 */
++		void newSessionIncoming();
++
++		/*
++		 * Emitted when a peer wants to remove 1 or more content(s)
++		 * from a session (content-remove action). It contains the
++		 * session id and a list of the contents to remove.
++		 */
++		void removeContent(const QString&, const QStringList&);
++
++		/*
++		 * Emitted when a peer sends a session information
++		 * (session-info jingle action).
++		 * In the case of RAW UDP transport, a session info can be an
++		 * informational message like "trying" or "received".
++		 * Argument is a QDomElement containing the jingle
++		 * tag (and children).
++		 */
++		void sessionInfo(const QDomElement&);
++
++		/*
++		 * Emitted when a peer sends a transport info.
++		 * In most cases, a transport-info jingle action
++		 * is used to transfer candidate(s).
++		 * Argument is a QDomElement containing the jingle
++		 * tag (and children).
++		 */
++		void transportInfo(const QDomElement&);
++
++		/*
++		 * Emitted when a peer wants to terminate a session
++		 * (session-terminate jingle action)
++		 * Arguments are the session ID and the Reason of the termination.
++		 */
++		void sessionTerminate(const QString&, const JingleReason&);
++
++		/*
++		 * Signal emitted when a session-accept jingle action has been received.
++		 */
++		void sessionAccepted(const QDomElement&);
++	
++	private:
++		class Private;
++		Private *d;
++
++		/* This method is called to acknowledge the stanza's sender.
++		 * before it is called, d->id must be set to the received
++		 * stanza's id.
++		 */
++		void ack();
++
++		/*
++		 * Called when an error iq stanza is received.
++		 * This method should do whatever it must be
++		 * done in the case of an error.
++		 * TODO:Implement me!
++		 */
++		void jingleError(const QDomElement&);
++	};
++
++	/*
++	 * This class is a task which is used to send all
++	 * possible jingle action to a contact, asked by a
++	 * JingleAction.
++	 */
++	class IRIS_EXPORT JT_JingleAction : public Task
++	{
++		Q_OBJECT
++	public:
++		JT_JingleAction(Task*);
++		~JT_JingleAction();
++		
++		void onGo();
++		bool take(const QDomElement&);
++		
++		/*
++		 * Before doing anything, this method must
++		 * be called to set the JingleSession pointer
++		 * so the task has all necessary information.
++		 */
++		void setSession(JingleSession*);
++		
++		/*
++		 * Send a session-initiate jingle action.
++		 * There is no argument as the JingleSession set
++		 * sooner must have all necessary information
++		 * (to, contents and sid)
++		 * In contents list, contents with raw-udp transport
++		 * must have a candidate set.
++		 */
++		void initiate();
++
++		/*
++		 * Send a session-terminate jingle action.
++		 * A reason is given as a parameter.
++		 */
++		void terminate(const JingleReason&);
++
++		/*
++		 * Send a content-accept jingle action.
++		 * TODO:should take a list of contents to accept.
++		 * 	Contents must be what we support, not the
++		 * 	contents we received in the session-initiate
++		 * 	jingle action.
++		 * TODO:(Re)implement me!
++		 */
++		void contentAccept();
++
++		/*
++		 * Send a content-remove jingle action.
++		 * The argument is a list containing the
++		 * content names to remove.
++		 */
++		void removeContents(const QStringList&);
++
++		/*
++		 * Sends a "ringing" informational message.
++		 * FIXME:Ringing is a session-info jingle action.
++		 * 	 It should be sent via a sessionInfo()
++		 * 	 method.
++		 */
++		void ringing();
++
++		/*
++		 * Sends a "trying" informational message.
++		 * FIXME:Same as ringing();
++		 */
++		void trying(const JingleContent&);
++
++		/*
++		 * Sends a "received" informational message.
++		 * FIXME:Same as ringing();
++		 */
++		void received();
++
++		/*
++		 * Sends a transport-info jingle action for a
++		 * content's transport.
++		 * Currently, this class sends candidate(s) for
++		 * the content's transport.
++		 */
++		void transportInfo(JingleContent *c);
++
++		/*
++		 * Sends a session-accept jingle action.
++		 * Once acked, this will mean the session is in the ACTIVE state
++		 */
++		void sessionAccept(const QList<JingleContent*>&);
++		
++	private :
++		class Private;
++		Private *d;
++	signals :
++		/*
++		 * This signal is emitted when the sent jingle
++		 * action has been acknowledged
++		 */
++		void finished();
++	
++	};
++}
++
++#endif
+diff -Nur iris-1.0.0/src/xmpp/modules.pri iris-1.0.0-023_jingle/src/xmpp/modules.pri
+--- iris-1.0.0/src/xmpp/modules.pri	2008-09-24 17:15:56.000000000 +0200
++++ iris-1.0.0-023_jingle/src/xmpp/modules.pri	2013-02-14 00:21:23.000000000 +0100
+@@ -4,3 +4,4 @@
+ IRIS_XMPP_BASE_MODULE = $$PWD/base/base.pri
+ IRIS_XMPP_ZLIB_MODULE = $$PWD/zlib/zlib.pri
+ IRIS_XMPP_BASE64_MODULE = $$PWD/base64/base64.pri
++IRIS_XMPP_JINGLE_MODULE = $$PWD/jingle/jingle.pri
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/client.cpp iris-1.0.0-023_jingle/src/xmpp/xmpp-im/client.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/client.cpp	2011-06-05 23:42:45.000000000 +0200
++++ iris-1.0.0-023_jingle/src/xmpp/xmpp-im/client.cpp	2013-02-14 00:31:20.000000000 +0100
+@@ -82,6 +82,7 @@
+ #include "xmpp_ibb.h"
+ #include "xmpp_bitsofbinary.h"
+ #include "filetransfer.h"
++#include "xmpp/jingle/jinglesessionmanager.h"
+ 
+ /*#include <stdio.h>
+ #include <stdarg.h>
+@@ -143,6 +144,7 @@
+ 	IBBManager *ibbman;
+ 	BoBManager *bobman;
+ 	FileTransferManager *ftman;
++	JingleSessionManager *jingleman;
+ 	bool ftEnabled;
+ 	QList<GroupChat> groupChatList;
+ };
+@@ -176,6 +178,7 @@
+ 	d->bobman = new BoBManager(this);
+ 
+ 	d->ftman = 0;
++	d->jingleman = 0L;
+ }
+ 
+ Client::~Client()
+@@ -183,6 +186,7 @@
+ 	close(true);
+ 
+ 	delete d->ftman;
++	delete d->jingleman;
+ 	delete d->ibbman;
+ 	delete d->s5bman;
+ 	delete d->root;
+@@ -251,6 +255,25 @@
+ 	return d->ftman;
+ }
+ 
++void Client::setJingleEnabled(bool b)
++{
++	if (b) {
++		if (!d->jingleman)
++			d->jingleman = new JingleSessionManager(this);
++	}
++	else {
++		if (d->jingleman) {
++			delete d->jingleman;
++			d->jingleman = 0L;
++		}
++	}
++}
++
++JingleSessionManager *Client::jingleSessionManager() const
++{
++	return d->jingleman;
++}
++
+ S5BManager *Client::s5bManager() const
+ {
+ 	return d->s5bman;
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_client.h iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_client.h
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_client.h	2011-06-05 23:42:45.000000000 +0200
++++ iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_client.h	2013-02-13 19:48:35.000000000 +0100
+@@ -35,6 +35,7 @@
+ 	class ClientStream;
+ 	class Features;
+ 	class FileTransferManager;
++	class JingleSessionManager;
+ 	class IBBManager;
+ 	class JidLinkManager;
+ 	class LiveRoster;
+@@ -125,6 +126,9 @@
+ 		void setFileTransferEnabled(bool b);
+ 		FileTransferManager *fileTransferManager() const;
+ 
++		void setJingleEnabled(bool b);
++		JingleSessionManager *jingleSessionManager() const;
++
+ 		QString groupChatPassword(const QString& host, const QString& room) const;
+ 		bool groupChatJoin(const QString &host, const QString &room, const QString &nick, const QString& password = QString(), int maxchars = -1, int maxstanzas = -1, int seconds = -1, const Status& = Status());
+ 		void groupChatSetStatus(const QString &host, const QString &room, const Status &);
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_features.cpp iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_features.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_features.cpp	2008-10-04 00:32:26.000000000 +0200
++++ iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_features.cpp	2013-02-13 19:48:35.000000000 +0100
+@@ -129,6 +129,41 @@
+ 	return test(ns);
+ }
+ 
++#define FID_JINGLE "urn:xmpp:tmp:jingle:0"
++bool Features::canJingle() const
++{
++       QStringList ns;
++       ns << FID_JINGLE;
++
++       return test(ns);
++}
++
++#define FID_JINGLERTP "urn:xmpp:tmp:jingle:apps:rtp:0"
++bool Features::canJingleRtp() const
++{
++       QStringList ns;
++       ns << FID_JINGLERTP;
++
++       return test(ns);
++}
++#define FID_JINGLERAW "urn:xmpp:jingle:transports:raw-udp:0"
++bool Features::canJingleRaw() const
++{
++       QStringList ns;
++       ns << FID_JINGLERAW;
++
++       return test(ns);
++}
++
++#define FID_JINGLEICE "urn:xmpp:jingle:transports:ice-udp:0"
++bool Features::canJingleIce() const
++{
++       QStringList ns;
++       ns << FID_JINGLEICE;
++
++       return test(ns);
++}
++
+ #define FID_GATEWAY "jabber:iq:gateway"
+ bool Features::isGateway() const
+ {
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_features.h iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_features.h
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_features.h	2007-09-20 20:39:14.000000000 +0200
++++ iris-1.0.0-023_jingle/src/xmpp/xmpp-im/xmpp_features.h	2013-02-13 19:48:35.000000000 +0100
+@@ -45,6 +45,10 @@
+ 		bool canMulticast() const;
+ 		bool canGroupchat() const;
+ 		bool canVoice() const;
++		bool canJingle() const;
++		bool canJingleRtp() const;
++		bool canJingleRaw() const;
++		bool canJingleIce() const;
+ 		bool canDisco() const;
+ 		bool canChatState() const;
+ 		bool canCommand() const;
+diff -Nur iris-1.0.0/src/xmpp/xmpp.pri iris-1.0.0-023_jingle/src/xmpp/xmpp.pri
+--- iris-1.0.0/src/xmpp/xmpp.pri	2011-02-23 22:42:16.000000000 +0100
++++ iris-1.0.0-023_jingle/src/xmpp/xmpp.pri	2013-02-14 00:21:32.000000000 +0100
+@@ -17,6 +17,7 @@
+ include($$IRIS_XMPP_ZLIB_MODULE)
+ include($$IRIS_XMPP_JID_MODULE)
+ include($$IRIS_XMPP_SASL_MODULE)
++include($$IRIS_XMPP_JINGLE_MODULE)
+ 
+ DEFINES += XMPP_TEST
+ 
diff --git a/iris-1.0.0-024_fix_semicolons_and_iterator.patch b/iris-1.0.0-024_fix_semicolons_and_iterator.patch
new file mode 100644
index 0000000..655276a
--- /dev/null
+++ b/iris-1.0.0-024_fix_semicolons_and_iterator.patch
@@ -0,0 +1,299 @@
+diff -Nur iris-1.0.0/src/irisnet/appledns/appledns.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/irisnet/appledns/appledns.cpp
+--- iris-1.0.0/src/irisnet/appledns/appledns.cpp	2008-09-20 01:38:52.000000000 +0200
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/irisnet/appledns/appledns.cpp	2013-02-13 23:03:05.000000000 +0100
+@@ -237,7 +237,7 @@
+ class AppleProvider : public XMPP::IrisNetProvider
+ {
+ 	Q_OBJECT
+-	Q_INTERFACES(XMPP::IrisNetProvider);
++	Q_INTERFACES(XMPP::IrisNetProvider)
+ public:
+ 	QDnsSd dns;
+ 	QHash<int,QDnsSdDelegate*> delegateById;
+diff -Nur iris-1.0.0/src/irisnet/corelib/jdnsshared.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/irisnet/corelib/jdnsshared.cpp
+--- iris-1.0.0/src/irisnet/corelib/jdnsshared.cpp	2009-04-16 19:11:02.000000000 +0200
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/irisnet/corelib/jdnsshared.cpp	2013-02-13 23:03:05.000000000 +0100
+@@ -442,7 +442,7 @@
+ 		None,            // don't muck with anything
+ 		FillInAddress,   // for A/AAAA
+ 		FillInPtrOwner6, // for PTR, IPv6
+-		FillInPtrOwner4, // for PTR, IPv4
++		FillInPtrOwner4 // for PTR, IPv4
+ 	};
+ 
+ 	JDnsShared *q;
+diff -Nur iris-1.0.0/src/irisnet/corelib/netinterface_unix.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/irisnet/corelib/netinterface_unix.cpp
+--- iris-1.0.0/src/irisnet/corelib/netinterface_unix.cpp	2011-07-12 20:10:43.000000000 +0200
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/irisnet/corelib/netinterface_unix.cpp	2013-02-13 23:03:05.000000000 +0100
+@@ -325,7 +325,7 @@
+ class UnixNet : public NetInterfaceProvider
+ {
+ 	Q_OBJECT
+-	Q_INTERFACES(XMPP::NetInterfaceProvider);
++	Q_INTERFACES(XMPP::NetInterfaceProvider)
+ public:
+ 	QList<Info> info;
+ 	QTimer t;
+@@ -413,7 +413,7 @@
+ class UnixNetProvider : public IrisNetProvider
+ {
+ 	Q_OBJECT
+-	Q_INTERFACES(XMPP::IrisNetProvider);
++	Q_INTERFACES(XMPP::IrisNetProvider)
+ public:
+ 	virtual NetInterfaceProvider *createNetInterfaceProvider()
+ 	{
+diff -Nur iris-1.0.0/src/irisnet/noncore/cutestuff/httppoll.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/irisnet/noncore/cutestuff/httppoll.cpp
+--- iris-1.0.0/src/irisnet/noncore/cutestuff/httppoll.cpp	2010-01-27 00:25:55.000000000 +0100
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/irisnet/noncore/cutestuff/httppoll.cpp	2013-02-13 23:03:05.000000000 +0100
+@@ -516,7 +516,7 @@
+ 
+ QString HttpProxyPost::getHeader(const QString &var) const
+ {
+-	for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it) {
++	for(QStringList::ConstIterator it = d->headerLines.constBegin(); it != d->headerLines.constEnd(); ++it) {
+ 		const QString &s = *it;
+ 		int n = s.indexOf(": ");
+ 		if(n == -1)
+@@ -761,7 +761,7 @@
+ 
+ QString HttpProxyGetStream::getHeader(const QString &var) const
+ {
+-	for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it) {
++	for(QStringList::ConstIterator it = d->headerLines.constBegin(); it != d->headerLines.constEnd(); ++it) {
+ 		const QString &s = *it;
+ 		int n = s.indexOf(": ");
+ 		if(n == -1)
+diff -Nur iris-1.0.0/src/irisnet/noncore/cutestuff/socks.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/irisnet/noncore/cutestuff/socks.cpp
+--- iris-1.0.0/src/irisnet/noncore/cutestuff/socks.cpp	2010-01-27 00:25:55.000000000 +0100
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/irisnet/noncore/cutestuff/socks.cpp	2013-02-13 23:02:53.000000000 +0100
+@@ -286,7 +286,7 @@
+ 		int at = 0;
+ 		quint16 c;
+ 		bool ok;
+-		for(QStringList::ConstIterator it = s6.begin(); it != s6.end(); ++it) {
++		for(QStringList::ConstIterator it = s6.constBegin(); it != s6.constEnd(); ++it) {
+ 			c = (*it).toInt(&ok, 16);
+ 			a6[at++] = (c >> 8);
+ 			a6[at++] = c & 0xff;
+diff -Nur iris-1.0.0/src/xmpp/sasl/digestmd5proplist.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/sasl/digestmd5proplist.cpp
+--- iris-1.0.0/src/xmpp/sasl/digestmd5proplist.cpp	2008-09-22 05:27:07.000000000 +0200
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/sasl/digestmd5proplist.cpp	2013-02-13 23:02:35.000000000 +0100
+@@ -34,7 +34,7 @@
+ 
+ QByteArray DIGESTMD5PropList::get(const QByteArray &var)
+ {
+-	for(ConstIterator it = begin(); it != end(); ++it) {
++	for(ConstIterator it = constBegin(); it != constEnd(); ++it) {
+ 		if((*it).var == var)
+ 			return (*it).val;
+ 	}
+@@ -123,7 +123,7 @@
+ int DIGESTMD5PropList::varCount(const QByteArray &var)
+ {
+ 	int n = 0;
+-	for(ConstIterator it = begin(); it != end(); ++it) {
++	for(ConstIterator it = constBegin(); it != constEnd(); ++it) {
+ 		if((*it).var == var)
+ 			++n;
+ 	}
+diff -Nur iris-1.0.0/src/xmpp/xmpp-core/parser.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-core/parser.cpp
+--- iris-1.0.0/src/xmpp/xmpp-core/parser.cpp	2008-08-19 01:03:07.000000000 +0200
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-core/parser.cpp	2013-02-13 23:03:05.000000000 +0100
+@@ -603,9 +603,9 @@
+ 
+ QString Parser::Event::nsprefix(const QString &s) const
+ {
+-	QStringList::ConstIterator it = d->nsnames.begin();
+-	QStringList::ConstIterator it2 = d->nsvalues.begin();
+-	for(; it != d->nsnames.end(); ++it) {
++	QStringList::ConstIterator it = d->nsnames.constBegin();
++	QStringList::ConstIterator it2 = d->nsvalues.constBegin();
++	for(; it != d->nsnames.constEnd(); ++it) {
+ 		if((*it) == s)
+ 			return (*it2);
+ 		++it2;
+diff -Nur iris-1.0.0/src/xmpp/xmpp-core/protocol.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-core/protocol.cpp
+--- iris-1.0.0/src/xmpp/xmpp-core/protocol.cpp	2008-09-24 23:14:45.000000000 +0200
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-core/protocol.cpp	2013-02-13 23:03:05.000000000 +0100
+@@ -404,7 +404,7 @@
+ 	// HACK: using attributes seems to be the only way to get additional namespaces in here
+ 	if(!defns.isEmpty())
+ 		e.setAttribute("xmlns", defns);
+-	for(QStringList::ConstIterator it = list.begin(); it != list.end();) {
++	for(QStringList::ConstIterator it = list.constBegin(); it != list.constEnd();) {
+ 		QString prefix = *(it++);
+ 		QString uri = *(it++);
+ 		e.setAttribute(QString("xmlns:") + prefix, uri);
+@@ -1267,7 +1267,7 @@
+ 		}
+ 		else {
+ 			QDomElement mechs = doc.createElementNS(NS_SASL, "mechanisms");
+-			for(QStringList::ConstIterator it = sasl_mechlist.begin(); it != sasl_mechlist.end(); ++it) {
++			for(QStringList::ConstIterator it = sasl_mechlist.constBegin(); it != sasl_mechlist.constEnd(); ++it) {
+ 				QDomElement m = doc.createElement("mechanism");
+ 				m.appendChild(doc.createTextNode(*it));
+ 				mechs.appendChild(m);
+diff -Nur iris-1.0.0/src/xmpp/xmpp-core/stream.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-core/stream.cpp
+--- iris-1.0.0/src/xmpp/xmpp-core/stream.cpp	2010-10-12 07:03:29.000000000 +0200
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-core/stream.cpp	2013-02-13 23:03:05.000000000 +0100
+@@ -926,7 +926,7 @@
+ #endif
+ 		bool ok = d->client.processStep();
+ 		// deal with send/received items
+-		for(QList<XmlProtocol::TransferItem>::ConstIterator it = d->client.transferItemList.begin(); it != d->client.transferItemList.end(); ++it) {
++		for(QList<XmlProtocol::TransferItem>::ConstIterator it = d->client.transferItemList.constBegin(); it != d->client.transferItemList.constEnd(); ++it) {
+ 			const XmlProtocol::TransferItem &i = *it;
+ 			if(i.isExternal)
+ 				continue;
+diff -Nur iris-1.0.0/src/xmpp/xmpp-core/xmpp.h iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-core/xmpp.h
+--- iris-1.0.0/src/xmpp/xmpp-core/xmpp.h	2010-03-06 02:49:47.000000000 +0100
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-core/xmpp.h	2013-02-13 23:03:05.000000000 +0100
+@@ -38,7 +38,7 @@
+ namespace QCA
+ {
+ 	class TLS;
+-};
++}
+ 
+ #ifndef CS_XMPP
+ class ByteStream;
+@@ -237,6 +237,6 @@
+ 		class Private;
+ 		Private *d;
+ 	};
+-};
++}
+ 
+ #endif
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/client.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-im/client.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/client.cpp	2011-06-05 23:42:45.000000000 +0200
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-im/client.cpp	2013-02-13 23:02:35.000000000 +0100
+@@ -342,7 +342,7 @@
+ {
+ 	Jid jid(room + "@" + host);
+ 	bool found = false;
+-	for(QList<GroupChat>::ConstIterator it = d->groupChatList.begin(); it != d->groupChatList.end(); it++) {
++	for(QList<GroupChat>::ConstIterator it = d->groupChatList.constBegin(); it != d->groupChatList.constEnd(); it++) {
+ 		const GroupChat &i = *it;
+ 		if(i.j.compare(jid, false)) {
+ 			found = true;
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/s5b.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-im/s5b.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/s5b.cpp	2011-02-27 21:56:36.000000000 +0100
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-im/s5b.cpp	2013-02-13 23:02:35.000000000 +0100
+@@ -1223,7 +1223,7 @@
+ 	S5BServer *serv = m->server();
+ 	if(serv && serv->isActive() && !haveHost(in_hosts, self)) {
+ 		QStringList hostList = serv->hostList();
+-		for(QStringList::ConstIterator it = hostList.begin(); it != hostList.end(); ++it) {
++		for(QStringList::ConstIterator it = hostList.constBegin(); it != hostList.constEnd(); ++it) {
+ 			StreamHost h;
+ 			h.setJid(self);
+ 			h.setHost(*it);
+@@ -1261,7 +1261,7 @@
+ 	StreamHostList list;
+ 	if(lateProxy) {
+ 		// take just the proxy streamhosts
+-		for(StreamHostList::ConstIterator it = in_hosts.begin(); it != in_hosts.end(); ++it) {
++		for(StreamHostList::ConstIterator it = in_hosts.constBegin(); it != in_hosts.constEnd(); ++it) {
+ 			if((*it).isProxy())
+ 				list += *it;
+ 		}
+@@ -1272,7 +1272,7 @@
+ 		if((state == Requester || (state == Target && fast)) && !proxy.jid().isValid()) {
+ 			// take just the non-proxy streamhosts
+ 			bool hasProxies = false;
+-			for(StreamHostList::ConstIterator it = in_hosts.begin(); it != in_hosts.end(); ++it) {
++			for(StreamHostList::ConstIterator it = in_hosts.constBegin(); it != in_hosts.constEnd(); ++it) {
+ 				if((*it).isProxy())
+ 					hasProxies = true;
+ 				else
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/types.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-im/types.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/types.cpp	2011-02-25 20:00:36.000000000 +0100
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-im/types.cpp	2013-02-13 23:02:35.000000000 +0100
+@@ -1467,7 +1467,7 @@
+ 		s.setLang(d->lang);
+ 
+ 	StringMap::ConstIterator it;
+-	for(it = d->subject.begin(); it != d->subject.end(); ++it) {
++	for(it = d->subject.constBegin(); it != d->subject.constEnd(); ++it) {
+ 		const QString &str = (*it);
+ 		if(!str.isNull()) {
+ 			QDomElement e = s.createTextElement(s.baseNS(), "subject", str);
+@@ -1476,7 +1476,7 @@
+ 			s.appendChild(e);
+ 		}
+ 	}
+-	for(it = d->body.begin(); it != d->body.end(); ++it) {
++	for(it = d->body.constBegin(); it != d->body.constEnd(); ++it) {
+ 		const QString &str = (*it);
+ 		if(!str.isEmpty()) {
+ 			QDomElement e = s.createTextElement(s.baseNS(), "body", str);
+@@ -1515,7 +1515,7 @@
+ 	}
+ 
+ 	// urls
+-	for(QList<Url>::ConstIterator uit = d->urlList.begin(); uit != d->urlList.end(); ++uit) {
++	for(QList<Url>::ConstIterator uit = d->urlList.constBegin(); uit != d->urlList.constEnd(); ++uit) {
+ 		QDomElement x = s.createElement("jabber:x:oob", "x");
+ 		x.appendChild(s.createTextElement("jabber:x:oob", "url", (*uit).url()));
+ 		if(!(*uit).desc().isEmpty())
+@@ -1534,7 +1534,7 @@
+ 				x.appendChild(s.createTextElement("jabber:x:event","id",d->eventId));
+ 		}
+ 
+-		for(QList<MsgEvent>::ConstIterator ev = d->eventList.begin(); ev != d->eventList.end(); ++ev) {
++		for(QList<MsgEvent>::ConstIterator ev = d->eventList.constBegin(); ev != d->eventList.constEnd(); ++ev) {
+ 			switch (*ev) {
+ 				case OfflineEvent:
+ 					x.appendChild(s.createElement("jabber:x:event", "offline"));
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_address.h iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-im/xmpp_address.h
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_address.h	2008-08-17 23:29:07.000000000 +0200
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-im/xmpp_address.h	2013-02-13 23:02:35.000000000 +0100
+@@ -61,6 +61,6 @@
+ 	};
+ 
+ 	typedef QList<Address> AddressList;
+-};
++}
+ 	
+ #endif
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_tasks.cpp iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-im/xmpp_tasks.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_tasks.cpp	2011-02-23 22:42:16.000000000 +0100
++++ iris-1.0.0-024_fix_semicolons_and_iterator/src/xmpp/xmpp-im/xmpp_tasks.cpp	2013-02-13 23:02:35.000000000 +0100
+@@ -425,7 +425,7 @@
+ 		QDomElement query = doc()->createElement("query");
+ 		query.setAttribute("xmlns", "jabber:iq:roster");
+ 		iq.appendChild(query);
+-		for(QList<QDomElement>::ConstIterator it = d->itemList.begin(); it != d->itemList.end(); ++it)
++		for(QList<QDomElement>::ConstIterator it = d->itemList.constBegin(); it != d->itemList.constEnd(); ++it)
+ 			query.appendChild(*it);
+ 		send(iq);
+ 	}
+@@ -443,7 +443,7 @@
+ 
+ 	QDomElement i = doc()->createElement("request");
+ 	i.setAttribute("type", "JT_Roster");
+-	for(QList<QDomElement>::ConstIterator it = d->itemList.begin(); it != d->itemList.end(); ++it)
++	for(QList<QDomElement>::ConstIterator it = d->itemList.constBegin(); it != d->itemList.constEnd(); ++it)
+ 		i.appendChild(*it);
+ 	return lineEncode(Stream::xmlToString(i));
+ 	return "";
+@@ -1500,7 +1500,7 @@
+ 
+ 			// Client-specific features
+ 			QStringList clientFeatures = client()->features().list();
+-			for (QStringList::ConstIterator i = clientFeatures.begin(); i != clientFeatures.end(); ++i) {
++			for (QStringList::ConstIterator i = clientFeatures.constBegin(); i != clientFeatures.constEnd(); ++i) {
+ 				feature = doc()->createElement("feature");
+ 				feature.setAttribute("var", *i);
+ 				query.appendChild(feature);
+@@ -1509,7 +1509,7 @@
+ 			if (node.isEmpty()) {
+ 				// Extended features
+ 				QStringList exts = client()->extensions();
+-				for (QStringList::ConstIterator i = exts.begin(); i != exts.end(); ++i) {
++				for (QStringList::ConstIterator i = exts.constBegin(); i != exts.constEnd(); ++i) {
+ 					const QStringList& l = client()->extension(*i).list();
+ 					for ( QStringList::ConstIterator j = l.begin(); j != l.end(); ++j ) {
+ 						feature = doc()->createElement("feature");
diff --git a/iris-1.0.0-027_add_socket_access_function.patch b/iris-1.0.0-027_add_socket_access_function.patch
new file mode 100644
index 0000000..aa2d2f6
--- /dev/null
+++ b/iris-1.0.0-027_add_socket_access_function.patch
@@ -0,0 +1,121 @@
+diff -Nur iris-1.0.0/src/irisnet/noncore/cutestuff/bsocket.cpp iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/bsocket.cpp
+--- iris-1.0.0/src/irisnet/noncore/cutestuff/bsocket.cpp	2010-03-06 02:49:47.000000000 +0100
++++ iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/bsocket.cpp	2013-02-13 23:08:51.000000000 +0100
+@@ -208,6 +208,11 @@
+ 	d->srv.resolve(srv, type, "tcp");
+ }
+ 
++QAbstractSocket* BSocket::abstractSocket() const
++{
++	return d->qsock;
++}
++
+ int BSocket::socket() const
+ {
+ 	if(d->qsock)
+diff -Nur iris-1.0.0/src/irisnet/noncore/cutestuff/bsocket.h iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/bsocket.h
+--- iris-1.0.0/src/irisnet/noncore/cutestuff/bsocket.h	2010-03-06 02:49:47.000000000 +0100
++++ iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/bsocket.h	2013-02-13 23:08:11.000000000 +0100
+@@ -43,6 +43,7 @@
+ 	void connectToHost(const QString &host, quint16 port);
+ 	void connectToHost(const QHostAddress &addr, quint16 port);
+ 	void connectToServer(const QString &srv, const QString &type);
++	virtual QAbstractSocket* abstractSocket() const;
+ 	int socket() const;
+ 	void setSocket(int);
+ 	int state() const;
+diff -Nur iris-1.0.0/src/irisnet/noncore/cutestuff/bytestream.h iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/bytestream.h
+--- iris-1.0.0/src/irisnet/noncore/cutestuff/bytestream.h	2008-06-02 20:37:53.000000000 +0200
++++ iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/bytestream.h	2013-02-13 23:08:28.000000000 +0100
+@@ -24,6 +24,7 @@
+ #include <QObject>
+ #include <QByteArray>
+ 
++class QAbstractSocket;
+ // CS_NAMESPACE_BEGIN
+ 
+ // CS_EXPORT_BEGIN
+@@ -45,6 +46,8 @@
+ 	static void appendArray(QByteArray *a, const QByteArray &b);
+ 	static QByteArray takeArray(QByteArray *from, int size=0, bool del=true);
+ 
++	virtual QAbstractSocket* abstractSocket() const { return 0; }
++
+ signals:
+ 	void connectionClosed();
+ 	void delayedCloseFinished();
+diff -Nur iris-1.0.0/src/irisnet/noncore/cutestuff/httppoll.cpp iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/httppoll.cpp
+--- iris-1.0.0/src/irisnet/noncore/cutestuff/httppoll.cpp	2010-01-27 00:25:55.000000000 +0100
++++ iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/httppoll.cpp	2013-02-13 23:08:37.000000000 +0100
+@@ -109,6 +109,11 @@
+ 	delete d;
+ }
+ 
++QAbstractSocket* HttpPoll::abstractSocket() const
++{
++	return d->http.abstractSocket();
++}
++
+ void HttpPoll::reset(bool clear)
+ {
+ 	if(d->http.isActive())
+@@ -465,6 +470,11 @@
+ 	delete d;
+ }
+ 
++QAbstractSocket* HttpProxyPost::abstractSocket() const
++{
++	return d->sock.abstractSocket();
++}
++
+ void HttpProxyPost::reset(bool clear)
+ {
+ 	if(d->sock.state() != BSocket::Idle)
+diff -Nur iris-1.0.0/src/irisnet/noncore/cutestuff/httppoll.h iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/httppoll.h
+--- iris-1.0.0/src/irisnet/noncore/cutestuff/httppoll.h	2007-09-20 20:39:14.000000000 +0200
++++ iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/httppoll.h	2013-02-13 23:08:59.000000000 +0100
+@@ -33,6 +33,8 @@
+ 	HttpPoll(QObject *parent=0);
+ 	~HttpPoll();
+ 
++	virtual QAbstractSocket* abstractSocket() const;
++
+ 	void setAuth(const QString &user, const QString &pass="");
+ 	void connectToUrl(const QString &url);
+ 	void connectToHost(const QString &proxyHost, int proxyPort, const QString &url);
+@@ -75,6 +77,8 @@
+ 	HttpProxyPost(QObject *parent=0);
+ 	~HttpProxyPost();
+ 
++	QAbstractSocket* abstractSocket() const;
++
+ 	void setAuth(const QString &user, const QString &pass="");
+ 	bool isActive() const;
+ 	void post(const QString &proxyHost, int proxyPort, const QString &url, const QByteArray &data, bool asProxy=true);
+diff -Nur iris-1.0.0/src/irisnet/noncore/cutestuff/socks.cpp iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/socks.cpp
+--- iris-1.0.0/src/irisnet/noncore/cutestuff/socks.cpp	2010-01-27 00:25:55.000000000 +0100
++++ iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/socks.cpp	2013-02-13 23:08:19.000000000 +0100
+@@ -477,6 +477,11 @@
+ 	delete d;
+ }
+ 
++QAbstractSocket* SocksClient::abstractSocket() const
++{
++	return d->sock.abstractSocket();
++}
++
+ void SocksClient::reset(bool clear)
+ {
+ 	if(d->sock.state() != BSocket::Idle)
+diff -Nur iris-1.0.0/src/irisnet/noncore/cutestuff/socks.h iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/socks.h
+--- iris-1.0.0/src/irisnet/noncore/cutestuff/socks.h	2008-06-02 21:09:45.000000000 +0200
++++ iris-1.0.0-027_add_socket_access_function/src/irisnet/noncore/cutestuff/socks.h	2013-02-13 23:08:43.000000000 +0100
+@@ -63,6 +63,8 @@
+ 	SocksClient(int, QObject *parent=0);
+ 	~SocksClient();
+ 
++	virtual QAbstractSocket* abstractSocket() const;
++
+ 	bool isIncoming() const;
+ 
+ 	// outgoing
diff --git a/iris-1.0.0-030_xep_0115_hash_attribute.patch b/iris-1.0.0-030_xep_0115_hash_attribute.patch
new file mode 100644
index 0000000..c1291cd
--- /dev/null
+++ b/iris-1.0.0-030_xep_0115_hash_attribute.patch
@@ -0,0 +1,138 @@
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/client.cpp iris-1.0.0-030_xep_0115_hash_attribute/src/xmpp/xmpp-im/client.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/client.cpp	2011-06-05 23:42:45.000000000 +0200
++++ iris-1.0.0-030_xep_0115_hash_attribute/src/xmpp/xmpp-im/client.cpp	2013-02-13 23:08:59.000000000 +0100
+@@ -129,7 +129,7 @@
+ 	int id_seed;
+ 	Task *root;
+ 	QString host, user, pass, resource;
+-	QString osname, tzname, clientName, clientVersion, capsNode, capsVersion, capsExt;
++	QString osname, tzname, clientName, clientVersion, capsNode, capsVersion, capsExt, capsHash;
+ 	DiscoItem::Identity identity;
+ 	Features features;
+ 	QMap<QString,Features> extension_features;
+@@ -161,6 +161,7 @@
+ 	d->capsNode = "";
+ 	d->capsVersion = "";
+ 	d->capsExt = "";
++	d->capsHash = "";
+ 
+ 	d->id_seed = 0xaaaa;
+ 	d->root = new Task(this, true);
+@@ -1070,6 +1071,11 @@
+ 	return d->capsExt;
+ }
+ 
++QString Client::capsHash() const
++{
++	return d->capsHash;
++}
++
+ void Client::setOSName(const QString &name)
+ {
+ 	d->osname = name;
+@@ -1102,6 +1108,11 @@
+ 	d->capsVersion = s;
+ }
+ 
++void Client::setCapsHash(const QString &s)
++{
++	d->capsHash = s;
++}
++
+ DiscoItem::Identity Client::identity()
+ {
+ 	return d->identity;
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/types.cpp iris-1.0.0-030_xep_0115_hash_attribute/src/xmpp/xmpp-im/types.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/types.cpp	2011-02-25 20:00:36.000000000 +0100
++++ iris-1.0.0-030_xep_0115_hash_attribute/src/xmpp/xmpp-im/types.cpp	2013-02-13 23:08:59.000000000 +0100
+@@ -2296,6 +2296,11 @@
+ 	v_capsExt = _capsExt;
+ }
+ 
++void Status::setCapsHash(const QString & _capsHash)
++{
++	v_capsHash = _capsHash;
++}
++
+ void Status::setMUC() 
+ {
+ 	v_isMUC = true;
+@@ -2450,6 +2455,11 @@
+ 	return v_capsExt;
+ }
+ 
++const QString & Status::capsHash() const
++{
++	return v_capsHash;
++}
++
+ bool Status::isMUC() const
+ {
+ 	return v_isMUC || !v_mucPassword.isEmpty() || hasMUCHistory();
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_client.h iris-1.0.0-030_xep_0115_hash_attribute/src/xmpp/xmpp-im/xmpp_client.h
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_client.h	2011-06-05 23:42:45.000000000 +0200
++++ iris-1.0.0-030_xep_0115_hash_attribute/src/xmpp/xmpp-im/xmpp_client.h	2013-02-13 23:08:59.000000000 +0100
+@@ -98,6 +98,7 @@
+ 		QString capsNode() const;
+ 		QString capsVersion() const;
+ 		QString capsExt() const;
++		QString capsHash() const;
+ 
+ 		void setOSName(const QString &);
+ 		void setTimeZone(const QString &, int);
+@@ -105,6 +106,7 @@
+ 		void setClientVersion(const QString &);
+ 		void setCapsNode(const QString &);
+ 		void setCapsVersion(const QString &);
++		void setCapsHash(const QString &);
+ 
+ 		void setIdentity(DiscoItem::Identity);
+ 		DiscoItem::Identity identity();
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_status.h iris-1.0.0-030_xep_0115_hash_attribute/src/xmpp/xmpp-im/xmpp_status.h
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_status.h	2011-01-24 20:21:56.000000000 +0100
++++ iris-1.0.0-030_xep_0115_hash_attribute/src/xmpp/xmpp-im/xmpp_status.h	2013-02-13 23:24:56.000000000 +0100
+@@ -58,6 +58,7 @@
+ 		const QString & capsNode() const;
+ 		const QString & capsVersion() const;
+ 		const QString & capsExt() const;
++		const QString & capsHash() const;
+ 		
+ 		bool isMUC() const;
+ 		bool hasMUCItem() const;
+@@ -84,6 +85,7 @@
+ 		void setCapsNode(const QString&);
+ 		void setCapsVersion(const QString&);
+ 		void setCapsExt(const QString&);
++		void setCapsHash(const QString&);
+ 		
+ 		void setMUC();
+ 		void setMUCItem(const MUCItem&);
+@@ -116,7 +118,7 @@
+ 		QString v_xsigned;
+ 		// gabber song extension
+ 		QString v_songTitle;
+-		QString v_capsNode, v_capsVersion, v_capsExt;
++		QString v_capsNode, v_capsVersion, v_capsExt, v_capsHash;
+ 		QList<BoBData> v_bobDataList;
+ 
+ 		// MUC
+diff -Nur iris-1.0.0/src/xmpp/xmpp-im/xmpp_tasks.cpp iris-1.0.0-030_xep_0115_hash_attribute/src/xmpp/xmpp-im/xmpp_tasks.cpp
+--- iris-1.0.0/src/xmpp/xmpp-im/xmpp_tasks.cpp	2011-02-23 22:42:16.000000000 +0100
++++ iris-1.0.0-030_xep_0115_hash_attribute/src/xmpp/xmpp-im/xmpp_tasks.cpp	2013-02-13 23:08:59.000000000 +0100
+@@ -589,6 +589,8 @@
+ 			c.setAttribute("ver",s.capsVersion());
+ 			if (!s.capsExt().isEmpty()) 
+ 				c.setAttribute("ext",s.capsExt());
++			if (!s.capsHash().isEmpty())
++				c.setAttribute("hash",s.capsHash());
+ 			tag.appendChild(c);
+ 		}
+ 
+@@ -759,6 +761,7 @@
+  			p.setCapsNode(i.attribute("node"));
+  			p.setCapsVersion(i.attribute("ver"));
+  			p.setCapsExt(i.attribute("ext"));
++			p.setCapsHash(i.attribute("hash"));
+   		}
+ 		else if(i.tagName() == "x" && i.attribute("xmlns") == "vcard-temp:x:update") {
+ 			QDomElement t;
diff --git a/iris-1.0.0-install_jingle.patch b/iris-1.0.0-install_jingle.patch
new file mode 100644
index 0000000..e376405
--- /dev/null
+++ b/iris-1.0.0-install_jingle.patch
@@ -0,0 +1,14 @@
+diff -up iris-1.0.0/iris.pro.install_jingle iris-1.0.0/iris.pro
+--- iris-1.0.0/iris.pro.install_jingle	2013-02-14 07:00:02.426980206 -0600
++++ iris-1.0.0/iris.pro	2013-02-14 07:14:10.891372941 -0600
+@@ -34,6 +34,10 @@ src/irisnet/corelib/irisnetexport.h \
+ src/irisnet/corelib/irisnetglobal.h \
+ src/irisnet/corelib/irisnetplugin.h \
+ src/irisnet/corelib/jdnsshared.h \
++src/xmpp/jingle/jinglesession.h \
++src/xmpp/jingle/jinglesessionmanager.h \
++src/xmpp/jingle/jinglecontent.h \
++src/xmpp/jingle/jingletasks.h \
+ src/irisnet/noncore/legacy/ndns.h \
+ src/irisnet/corelib/netavailability.h \
+ src/irisnet/corelib/netinterface.h \
diff --git a/iris.spec b/iris.spec
index 99ce573..16e82e5 100644
--- a/iris.spec
+++ b/iris.spec
@@ -5,7 +5,7 @@
 Name:    iris
 Summary: A library for working with the XMPP/Jabber protocol 
 Version: 1.0.0
-Release: 0.12.%{snap}svn%{svn}%{?dist}
+Release: 0.13.%{snap}svn%{svn}%{?dist}
 License: LGPLv2+
 URL:     http://delta.affinix.com/iris/
 # svn export https://delta.affinix.com/svn/trunk/iris iris-1.0.0
@@ -32,8 +32,17 @@ Patch2: iris-1.0.0-system_libidn.patch
 # install jdns
 Patch3: iris-1.0.0-jdns_install.patch
 
-## TODO/FIXME
-# * verfiy author/license of src/xmmp/base64
+## rebased patches from kopete
+Patch103: iris-1.0.0-003_case_insensitive_jid.patch
+Patch109: iris-1.0.0-009_filetransferpreview.patch
+Patch114: iris-1.0.0-014_fix_semicolons.patch
+Patch123: iris-1.0.0-023_jingle.patch
+# followup to patch123, to install new headers
+Patch223: iris-1.0.0-install_jingle.patch
+Patch124: iris-1.0.0-024_fix_semicolons_and_iterator.patch
+Patch127: iris-1.0.0-027_add_socket_access_function.patch
+Patch130: iris-1.0.0-030_xep_0115_hash_attribute.patch
+
 
 %description
 %{summary}.
@@ -72,6 +81,15 @@ Requires: qjdns%{?_isa} = %{version}-%{release}
 mv src/libidn src/libidn.BAK
 %patch3 -p1 -b .jdns_install
 
+%patch103 -p1 -b .003
+%patch109 -p1 -b .009
+%patch114 -p1 -b .014
+%patch123 -p1 -b .023
+%patch223 -p1 -b .223
+%patch124 -p1 -b .024
+%patch127 -p1 -b .027
+%patch130 -p1 -b .030
+
 
 %build
 ./configure \
@@ -129,6 +147,9 @@ test "$(pkg-config --modversion qjdns)" = "%{version}"
 
 
 %changelog
+* Thu Feb 14 2013 Rex Dieter <rdieter at fedoraproject.org> 1.0.0-0.13.20110904svn812
+- port/rebase kopete patches (kudos to kkofler)
+
 * Mon Feb 11 2013 Rex Dieter <rdieter at fedoraproject.org> - 1.0.0-0.12.20110904svn812
 - iris.pc: +Requires: qca2
 - system_libidn.patch: link against system libidn too


More information about the scm-commits mailing list