aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorManjeet Dahiya <manjeetdahiya@gmail.com>2009-10-27 12:04:03 +0000
committerManjeet Dahiya <manjeetdahiya@gmail.com>2009-10-27 12:04:03 +0000
commit10c093a617929db5c6b201dbf03d6070b12b36b4 (patch)
treed9b1c4507fdb1969c3225f27b4632258c4916dc0 /source
parent239b2b15c3cfd9e4d7cc085ed31645d6ae6942ee (diff)
downloadqxmpp-10c093a617929db5c6b201dbf03d6070b12b36b4.tar.gz
Issue 15: Implement XEP-0047
Diffstat (limited to 'source')
-rw-r--r--source/QXmppBind.cpp3
-rw-r--r--source/QXmppClient.cpp10
-rw-r--r--source/QXmppClient.h3
-rw-r--r--source/QXmppConfiguration.h6
-rw-r--r--source/QXmppDataIq.cpp69
-rw-r--r--source/QXmppDataIq.h30
-rw-r--r--source/QXmppIbbIqs.cpp202
-rw-r--r--source/QXmppIbbIqs.h70
-rw-r--r--source/QXmppIbbTransferJob.cpp230
-rw-r--r--source/QXmppIbbTransferJob.h66
-rw-r--r--source/QXmppIbbTransferManager.cpp95
-rw-r--r--source/QXmppIbbTransferManager.h60
-rw-r--r--source/QXmppStanza.cpp2
-rw-r--r--source/QXmppStanza.h2
-rw-r--r--source/QXmppStream.cpp55
-rw-r--r--source/QXmppUtils.cpp13
-rw-r--r--source/QXmppUtils.h1
-rw-r--r--source/source.pro27
18 files changed, 921 insertions, 23 deletions
diff --git a/source/QXmppBind.cpp b/source/QXmppBind.cpp
index a1c5bd25..3742660b 100644
--- a/source/QXmppBind.cpp
+++ b/source/QXmppBind.cpp
@@ -64,9 +64,6 @@ void QXmppBind::setResource(const QString& str)
void QXmppBind::toXmlElementFromChild(QXmlStreamWriter *writer) const
{
- QString data;
- QTextStream stream(&data);
-
writer->writeStartElement("bind");
helperToXmlAddAttribute(writer, "xmlns", ns_bind);
helperToXmlAddTextElement(writer, "jid", getJid() );
diff --git a/source/QXmppClient.cpp b/source/QXmppClient.cpp
index 0538224f..a98caa01 100644
--- a/source/QXmppClient.cpp
+++ b/source/QXmppClient.cpp
@@ -27,6 +27,7 @@
#include "QXmppRoster.h"
#include "QXmppMessage.h"
#include "QXmppReconnectionManager.h"
+#include "QXmppIbbTransferManager.h"
/// Creates a QXmppClient object.
/// \param parent is passed to the QObject's contructor.
@@ -34,7 +35,7 @@
QXmppClient::QXmppClient(QObject *parent)
: QObject(parent), m_stream(0), m_clientPrecence(QXmppPresence::Available),
- m_reconnectionManager(0)
+ m_reconnectionManager(0), m_ibbTransferManager(0)
{
m_stream = new QXmppStream(this);
@@ -63,6 +64,8 @@ QXmppClient::QXmppClient(QObject *parent)
check = setReconnectionManager(new QXmppReconnectionManager(this));
Q_ASSERT(check);
+
+ m_ibbTransferManager = new QXmppIbbTransferManager(this);
}
/// Destroys the QXmppClient object.
@@ -337,3 +340,8 @@ QXmppVCardManager& QXmppClient::getVCardManager()
{
return m_stream->getVCardManager();
}
+
+QXmppIbbTransferManager* QXmppClient::getIbbTransferManager() const
+{
+ return m_ibbTransferManager;
+}
diff --git a/source/QXmppClient.h b/source/QXmppClient.h
index 5e5f3099..ad24187a 100644
--- a/source/QXmppClient.h
+++ b/source/QXmppClient.h
@@ -52,6 +52,7 @@ class QXmppIq;
class QXmppRoster;
class QXmppReconnectionManager;
class QXmppVCardManager;
+class QXmppIbbTransferManager;
class QXmppClient : public QObject
{
@@ -87,6 +88,7 @@ public:
bool setReconnectionManager(QXmppReconnectionManager*);
const QXmppPresence& getClientPresence() const;
QXmppVCardManager& getVCardManager();
+ QXmppIbbTransferManager* getIbbTransferManager() const;
signals:
@@ -155,6 +157,7 @@ private:
///< required for connecting to the XMPP server.
QXmppPresence m_clientPrecence; ///< Stores the current presence of connected client
QXmppReconnectionManager* m_reconnectionManager; ///< Pointer to the reconnection manager
+ QXmppIbbTransferManager* m_ibbTransferManager; ///< Pointer to the ibb transfer manager
};
#endif // QXMPPCLIENT_H
diff --git a/source/QXmppConfiguration.h b/source/QXmppConfiguration.h
index 953fe932..a1d0c0e7 100644
--- a/source/QXmppConfiguration.h
+++ b/source/QXmppConfiguration.h
@@ -93,12 +93,10 @@ public:
QXmppConfiguration::StreamSecurityMode getStreamSecurityMode() const;
void setStreamSecurityMode(QXmppConfiguration::StreamSecurityMode mode);
- QXmppConfiguration::NonSASLAuthMechanism QXmppConfiguration::
- getNonSASLAuthMechanism() const;
+ QXmppConfiguration::NonSASLAuthMechanism getNonSASLAuthMechanism() const;
void setNonSASLAuthMechanism(QXmppConfiguration::NonSASLAuthMechanism);
- QXmppConfiguration::SASLAuthMechanism QXmppConfiguration::
- getSASLAuthMechanism() const;
+ QXmppConfiguration::SASLAuthMechanism getSASLAuthMechanism() const;
void setSASLAuthMechanism(QXmppConfiguration::SASLAuthMechanism);
void setNetworkProxy(const QNetworkProxy& proxy);
diff --git a/source/QXmppDataIq.cpp b/source/QXmppDataIq.cpp
new file mode 100644
index 00000000..a1fcda23
--- /dev/null
+++ b/source/QXmppDataIq.cpp
@@ -0,0 +1,69 @@
+#include "QXmppDataIq.h"
+#include "QXmppConstants.h"
+
+#include <QXmlStreamWriter>
+#include <QDomElement>
+
+QXmppDataIq::QXmppDataIq() : QXmppIq( QXmppIq::Set ), m_seq(0)
+{
+}
+
+quint16 QXmppDataIq::getSequence() const
+{
+ return m_seq;
+}
+
+void QXmppDataIq::setSequence( quint16 seq )
+{
+ m_seq = seq;
+}
+
+QString QXmppDataIq::getSid() const
+{
+ return m_sid;
+}
+
+void QXmppDataIq::setSid( const QString &sid )
+{
+ m_sid = sid;
+}
+
+QByteArray QXmppDataIq::getPayload() const
+{
+ return m_payload;
+}
+
+void QXmppDataIq::setPayload( const QByteArray &data )
+{
+ m_payload = data;
+}
+
+
+void QXmppDataIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement("data");
+ writer->writeAttribute( "xmlns",ns_ibb);
+ writer->writeAttribute( "sid",m_sid);
+ writer->writeAttribute( "seq",QString::number(m_seq) );
+ writer->writeCharacters( m_payload.toBase64() );
+ writer->writeEndElement();
+}
+
+void QXmppDataIq::parse( QDomElement &element )
+{
+ QDomElement dataElement = element.firstChildElement("data");
+ setId( element.attribute("id"));
+ setTo( element.attribute("to"));
+ setFrom( element.attribute("from"));
+ setTypeFromStr( element.attribute("type"));
+
+ m_sid = dataElement.attribute( "sid" );
+ m_seq = dataElement.attribute( "seq" ).toLong();
+ m_payload = QByteArray::fromBase64( dataElement.text().toLatin1() );
+}
+
+bool QXmppDataIq::isDataIq( QDomElement &element )
+{
+ QDomElement dataElement = element.firstChildElement("data");
+ return dataElement.namespaceURI() == ns_ibb;
+}
diff --git a/source/QXmppDataIq.h b/source/QXmppDataIq.h
new file mode 100644
index 00000000..0a987d29
--- /dev/null
+++ b/source/QXmppDataIq.h
@@ -0,0 +1,30 @@
+#ifndef QXMPPDATAIQ_H
+#define QXMPPDATAIQ_H
+
+#include "QXmppIq.h"
+
+class QXmlStreamWriter;
+class QDomElement;
+
+class QXmppDataIq : public QXmppIq
+{
+public:
+ QXmppDataIq();
+
+ quint16 getSequence() const;
+ void setSequence( quint16 seq );
+ QString getSid() const;
+ void setSid( const QString &sid );
+ QByteArray getPayload() const;
+ void setPayload( const QByteArray &data );
+
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parse( QDomElement &element );
+ static bool isDataIq( QDomElement &element );
+private:
+ quint16 m_seq;
+ QString m_sid;
+ QByteArray m_payload;
+};
+
+#endif // QXMPPDATAIQ_H
diff --git a/source/QXmppIbbIqs.cpp b/source/QXmppIbbIqs.cpp
new file mode 100644
index 00000000..f90dfbb1
--- /dev/null
+++ b/source/QXmppIbbIqs.cpp
@@ -0,0 +1,202 @@
+#include "QXmppIbbIqs.h"
+#include "QXmppConstants.h"
+
+#include <QDomElement>
+#include <QXmlStreamWriter>
+
+QXmppIbbOpenIq::QXmppIbbOpenIq() : QXmppIq(QXmppIq::Set), m_block_size(1024)
+{
+
+}
+
+void QXmppIbbOpenIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement("open");
+ writer->writeAttribute( "xmlns",ns_ibb);
+ writer->writeAttribute( "sid",m_sid);
+ writer->writeAttribute( "block-size",QString::number(m_block_size) );
+ writer->writeEndElement();
+}
+
+void QXmppIbbOpenIq::parse( QDomElement &element )
+{
+ QDomElement openElement = element.firstChildElement("open");
+ setId( element.attribute("id"));
+ setTo( element.attribute("to"));
+ setFrom( element.attribute("from"));
+ setTypeFromStr( element.attribute("type"));
+ m_sid = openElement.attribute( "sid" );
+ m_block_size = openElement.attribute( "block-size" ).toLong();
+}
+
+bool QXmppIbbOpenIq::isIbbOpenIq( QDomElement &element )
+{
+ QDomElement openElement = element.firstChildElement("open");
+ return openElement.namespaceURI() == ns_ibb;
+}
+
+long QXmppIbbOpenIq::getBlockSize() const
+{
+ return m_block_size;
+}
+
+void QXmppIbbOpenIq::setBlockSize( long block_size )
+{
+ m_block_size = block_size;
+}
+
+QString QXmppIbbOpenIq::getSid() const
+{
+ return m_sid;
+}
+
+void QXmppIbbOpenIq::setSid( const QString &sid )
+{
+ m_sid = sid;
+}
+
+QXmppIbbAckIq::QXmppIbbAckIq() : QXmppIq(QXmppIq::Result)
+{
+
+}
+
+void QXmppIbbAckIq::parse( QDomElement &element )
+{
+ setId( element.attribute("id"));
+ setTo( element.attribute("to"));
+ setFrom( element.attribute("from"));
+ setTypeFromStr( element.attribute("type"));
+}
+bool QXmppIbbAckIq::isIbbAckIq( QDomElement &element )
+{
+ return element.attribute("type") == "result";
+}
+
+QXmppIbbErrorIq::QXmppIbbErrorIq() : QXmppIq(QXmppIq::Error), m_type(Unknown)
+{
+
+}
+
+void QXmppIbbErrorIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement("error");
+ switch( m_type ) {
+ case Unknown:
+ break;
+ case Cancel:
+ writer->writeAttribute("type", "cancel");
+ writer->writeStartElement("not-acceptable");
+ break;
+ case NoSupport:
+ writer->writeAttribute("type", "cancel");
+ writer->writeStartElement("service-unavailable");
+ break;
+ case Modify:
+ writer->writeAttribute("type", "modify");
+ writer->writeStartElement("resource-constrainte");
+ break;
+ case NotFound:
+ writer->writeAttribute("type", "cancel");
+ writer->writeStartElement("item-not-found");
+ break;
+ }
+
+ writer->writeAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
+ writer->writeEndElement();
+ writer->writeEndElement();
+}
+
+void QXmppIbbErrorIq::parse( QDomElement &element )
+{
+ QDomElement errorElement = element.firstChildElement("error");
+ setId( element.attribute("id"));
+ setTo( element.attribute("to"));
+ setFrom( element.attribute("from"));
+ setTypeFromStr( element.attribute("type"));
+ if ( errorElement.attribute( "type" ) == "cancel" )
+ {
+ if( !errorElement.firstChildElement("service-unavailable").isNull() )
+ m_type = NoSupport;
+ else if( !errorElement.firstChildElement("not-acceptable").isNull() )
+ m_type = Cancel;
+ else if( !errorElement.firstChildElement("item-not-found").isNull() )
+ m_type = NotFound;
+ else
+ m_type = Unknown;
+ }
+ else if ( errorElement.attribute( "type" ) == "modify" )
+ {
+ if( !errorElement.firstChildElement("resource-constraint").isNull() )
+ m_type = Modify;
+ else
+ m_type = Unknown;
+ }
+ else
+ m_type = Unknown;
+ m_errorString = errorElement.text();
+
+}
+
+bool QXmppIbbErrorIq::isIbbErrorIq( QDomElement &element )
+{
+ return element.attribute("type") == "error";
+}
+
+QXmppIbbErrorIq::Type QXmppIbbErrorIq::getErrorType() const
+{
+ return m_type;
+}
+
+void QXmppIbbErrorIq::setErrorType( Type err )
+{
+ m_type = err;
+}
+
+QString QXmppIbbErrorIq::getErrorString() const
+{
+ return m_errorString;
+}
+
+void QXmppIbbErrorIq::setErrorString( const QString &err )
+{
+ m_errorString = err;
+}
+
+QXmppIbbCloseIq::QXmppIbbCloseIq() : QXmppIq(QXmppIq::Set)
+{
+
+}
+
+void QXmppIbbCloseIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
+{
+ writer->writeStartElement("close");
+ writer->writeAttribute( "xmlns",ns_ibb);
+ writer->writeAttribute( "sid",m_sid);
+ writer->writeEndElement();
+}
+
+void QXmppIbbCloseIq::parse( QDomElement &element )
+{
+ QDomElement openElement = element.firstChildElement("close");
+ setId( element.attribute("id"));
+ setTo( element.attribute("to"));
+ setFrom( element.attribute("from"));
+ setTypeFromStr( element.attribute("type"));
+ m_sid = openElement.attribute( "sid" );
+}
+
+bool QXmppIbbCloseIq::isIbbCloseIq( QDomElement &element )
+{
+ QDomElement openElement = element.firstChildElement("close");
+ return openElement.namespaceURI() == ns_ibb;
+}
+
+QString QXmppIbbCloseIq::getSid() const
+{
+ return m_sid;
+}
+
+void QXmppIbbCloseIq::setSid( const QString &sid )
+{
+ m_sid = sid;
+}
diff --git a/source/QXmppIbbIqs.h b/source/QXmppIbbIqs.h
new file mode 100644
index 00000000..058a1a85
--- /dev/null
+++ b/source/QXmppIbbIqs.h
@@ -0,0 +1,70 @@
+#ifndef QXMPPIBBIQS_H
+#define QXMPPIBBIQS_H
+
+#include "QXmppIq.h"
+
+class QDomElement;
+class QXmlStreamWriter;
+
+class QXmppIbbOpenIq: public QXmppIq
+{
+public:
+ QXmppIbbOpenIq();
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parse( QDomElement &element );
+ static bool isIbbOpenIq( QDomElement &element );
+
+ long getBlockSize() const;
+ void setBlockSize( long block_size );
+
+ QString getSid() const;
+ void setSid( const QString &sid );
+
+private:
+ long m_block_size;
+ QString m_sid;
+};
+
+class QXmppIbbAckIq: public QXmppIq
+{
+public:
+ QXmppIbbAckIq();
+ void parse( QDomElement &element );
+ static bool isIbbAckIq( QDomElement &element );
+};
+
+class QXmppIbbErrorIq: public QXmppIq
+{
+public:
+ enum Type { Unknown, Cancel, NoSupport, Modify, NotFound };
+ QXmppIbbErrorIq();
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parse( QDomElement &element );
+ static bool isIbbErrorIq( QDomElement &element );
+
+ Type getErrorType() const;
+ void setErrorType( Type err );
+
+ QString getErrorString() const;
+ void setErrorString( const QString &err );
+
+private:
+ Type m_type;
+ QString m_errorString;
+};
+
+class QXmppIbbCloseIq: public QXmppIq
+{
+public:
+ QXmppIbbCloseIq();
+ void toXmlElementFromChild(QXmlStreamWriter *writer) const;
+ void parse( QDomElement &element );
+ static bool isIbbCloseIq( QDomElement &element );
+
+ QString getSid() const;
+ void setSid( const QString &sid );
+
+private:
+ QString m_sid;
+};
+#endif // QXMPPIBBIQS_H
diff --git a/source/QXmppIbbTransferJob.cpp b/source/QXmppIbbTransferJob.cpp
new file mode 100644
index 00000000..4835596a
--- /dev/null
+++ b/source/QXmppIbbTransferJob.cpp
@@ -0,0 +1,230 @@
+#include "QXmppIbbTransferJob.h"
+
+#include <QIODevice>
+#include <QUuid>
+#include "QXmppIbbIqs.h"
+#include "QXmppDataIq.h"
+#include "QXmppClient.h"
+#include "QXmppUtils.h"
+
+QXmppIbbTransferJob::QXmppIbbTransferJob( QXmppClient *parent )
+ : QObject (parent ), m_client(parent), m_io(0), m_blockSize(4096),
+ m_streamBlockSize(0), m_sequence(0), m_state(Idle)
+{
+ m_localJid = parent->getConfiguration().getJid();
+ m_id = generateStanzaHash();
+ m_sid = generateStanzaHash();
+}
+
+QXmppIbbTransferJob::~QXmppIbbTransferJob()
+{
+}
+
+QString QXmppIbbTransferJob::getSid() const
+{
+ return m_sid;
+}
+
+void QXmppIbbTransferJob::setSid( const QString &sid )
+{
+ m_sid = sid;
+}
+
+void QXmppIbbTransferJob::setRemoteJid( const QString &jid )
+{
+ m_remoteJid = jid;
+}
+
+QString QXmppIbbTransferJob::getRemoteJid( ) const
+{
+ return m_remoteJid;
+}
+
+QString QXmppIbbTransferJob::getId() const
+{
+ return m_id;
+}
+
+void QXmppIbbTransferJob::setId( const QString &id )
+{
+ m_id = id;
+}
+
+
+void QXmppIbbTransferJob::requestTransfer( )
+{
+ m_state = Requesting;
+ QXmppIbbOpenIq request;
+ request.setBlockSize(m_blockSize);
+ request.setTo( m_remoteJid );
+ request.setFrom( m_localJid );
+ request.setSid( m_sid );
+ request.generateAndSetNextId();
+ m_id = request.getId();
+
+ m_client->sendPacket( request );
+
+}
+
+void QXmppIbbTransferJob::acceptTransfer( )
+{
+ if( m_state != Pending )
+ {
+ return;
+ }
+
+ m_state = TransferringIn;
+ QXmppIbbAckIq ack;
+ ack.setTo( m_remoteJid );
+ ack.setFrom( m_localJid );
+ ack.setId( m_id );
+ m_client->sendPacket( ack );
+ emit transferStarted(m_sid);
+}
+
+void QXmppIbbTransferJob::cancelTransfer( )
+{
+ QXmppIbbErrorIq cancel;
+ cancel.setId(m_id);
+ cancel.setErrorType( QXmppIbbErrorIq::Cancel );
+ m_client->sendPacket( cancel );
+}
+
+void QXmppIbbTransferJob::setIoDevice( QIODevice *io )
+{
+ m_io = io;
+}
+
+void QXmppIbbTransferJob::setBlockSize( long size)
+{
+ m_blockSize = size;
+}
+
+void QXmppIbbTransferJob::gotAck()
+{
+ if( m_state == Requesting )
+ {
+ // start transfer
+ m_state = TransferringOut;
+ sendNextBlock();
+ }
+ else if ( m_state == TransferringOut )
+ {
+ // send next packet
+ sendNextBlock();
+ }
+ else if ( m_state == Idle )
+ {
+ emit readyForTeardown(m_sid);
+ }
+ else
+ {
+
+ }
+}
+
+void QXmppIbbTransferJob::gotOpen( const QXmppIbbOpenIq &open )
+{
+ m_sid = open.getSid();
+ m_id = open.getId();
+ m_remoteJid = open.getFrom();
+ if( open.getBlockSize() > m_blockSize )
+ {
+ // cancel
+ m_state = Idle;
+ QXmppIbbErrorIq modifyError;
+ modifyError.setId(m_id);
+ modifyError.setErrorType( QXmppIbbErrorIq::Modify );
+ m_client->sendPacket( modifyError );
+ emit readyForTeardown(m_sid);
+ }
+ else
+ {
+ m_streamBlockSize = open.getBlockSize();
+ m_state = Pending;
+ emit transferRequested( m_sid , m_remoteJid );
+ }
+}
+
+void QXmppIbbTransferJob::gotClose( const QXmppIbbCloseIq &close )
+{
+ m_state = Idle;
+ QXmppIbbAckIq ack;
+ ack.setTo( m_remoteJid );
+ ack.setFrom( m_localJid );
+ ack.setId( m_id );
+ m_client->sendPacket( ack );
+ emit transferFinished(m_sid, "Closed");
+ emit readyForTeardown(m_sid);
+}
+
+void QXmppIbbTransferJob::gotError( const QXmppIbbErrorIq &err )
+{
+ m_state = Idle;
+ emit transferCanceled(m_sid,err.getError().getConditionStr());
+ emit readyForTeardown(m_sid);
+}
+void QXmppIbbTransferJob::gotData( const QXmppDataIq &data )
+{
+ if( m_io &&
+ (data.getSequence() == 0 || data.getSequence() > m_sequence) )
+ {
+ m_io->write( data.getPayload() );
+ m_sequence = data.getSequence();
+ QXmppIbbAckIq ack;
+ ack.setId(m_id);
+ ack.setTo(m_remoteJid);
+ ack.setFrom(m_localJid);
+ m_client->sendPacket( ack );
+ }
+ else
+ {
+ QXmppIbbErrorIq error;
+ error.setId(m_id);
+ error.setTo(m_remoteJid);
+ error.setFrom(m_localJid);
+ error.setErrorType(QXmppIbbErrorIq::Cancel);
+ m_client->sendPacket( error );
+ }
+}
+
+void QXmppIbbTransferJob::sendNextBlock()
+{
+
+ if( m_io == 0 || !m_io->isReadable() )
+ {
+ QXmppIbbErrorIq error;
+ error.setId(m_id);
+ error.setTo(m_remoteJid);
+ error.setFrom(m_localJid);
+ error.setErrorType(QXmppIbbErrorIq::Cancel);
+ m_client->sendPacket( error );
+ }
+ else if( m_io->atEnd() || !m_io->isOpen() )
+ {
+ QXmppIbbCloseIq close;
+ close.setId(m_id);
+ close.setTo(m_remoteJid);
+ close.setFrom(m_localJid);
+ close.setSid(m_sid);
+ m_client->sendPacket( close );
+ m_state = Idle;
+ emit transferFinished(m_sid, "Send finished");
+ }
+ else
+ {
+ //FIXME: work better with sockets and other stream devices.
+ QByteArray buffer = m_io->read( m_blockSize );
+
+ m_sequence++;
+ QXmppDataIq sendData;
+ sendData.setId(m_id);
+ sendData.setTo(m_remoteJid);
+ sendData.setFrom(m_localJid);
+ sendData.setSid(m_sid);
+ sendData.setSequence(m_sequence);
+ sendData.setPayload( buffer );
+
+ m_client->sendPacket( sendData );
+ }
+}
diff --git a/source/QXmppIbbTransferJob.h b/source/QXmppIbbTransferJob.h
new file mode 100644
index 00000000..2c14c03d
--- /dev/null
+++ b/source/QXmppIbbTransferJob.h
@@ -0,0 +1,66 @@
+#ifndef QXMPPIBBTRANSFERJOB_H
+#define QXMPPIBBTRANSFERJOB_H
+
+#include <QObject>
+class QIODevice;
+class QXmppIbbOpenIq;
+class QXmppIbbCloseIq;
+class QXmppIbbErrorIq;
+class QXmppDataIq;
+class QXmppClient;
+
+class QXmppIbbTransferJob : public QObject
+{
+ Q_OBJECT
+public:
+
+ QXmppIbbTransferJob(QXmppClient *parent = 0);
+ ~QXmppIbbTransferJob();
+ QString getSid() const;
+ void setSid( const QString &sid );
+ QString getRemoteJid( ) const;
+ void setRemoteJid( const QString &jid );
+ QString getId() const;
+ void setId( const QString &id );
+
+// Used by the client
+public slots:
+ void requestTransfer( );
+ void acceptTransfer( );
+ void cancelTransfer( );
+
+signals:
+ void transferRequested( const QString &sid, const QString &remoteJid );
+ void transferStarted( const QString &sid );
+ void transferFinished( const QString &sid, const QString &reason);
+ void transferCanceled( const QString &sid, const QString &reason );
+ void readyForTeardown( const QString &sid );
+
+public:
+ void setIoDevice( QIODevice *io );
+ void setBlockSize( long size);
+
+ // Used by the stream.
+ void gotAck();
+ void gotOpen( const QXmppIbbOpenIq &open );
+ void gotClose( const QXmppIbbCloseIq &close );
+ void gotError( const QXmppIbbErrorIq &err );
+ void gotData( const QXmppDataIq &data );
+
+private:
+ enum TransferState { Idle, Requesting, Pending, TransferringIn, TransferringOut };
+ void sendNextBlock();
+
+ QXmppClient *m_client;
+ QIODevice *m_io;
+ long m_blockSize;
+ qint64 m_streamBlockSize;
+ quint16 m_sequence;
+ QString m_sid;
+ QString m_id;
+ QString m_localJid;
+ QString m_remoteJid;
+ TransferState m_state;
+};
+
+#endif // QXMPPIBBTRANSFERJOB_H
diff --git a/source/QXmppIbbTransferManager.cpp b/source/QXmppIbbTransferManager.cpp
new file mode 100644
index 00000000..e9437b5b
--- /dev/null
+++ b/source/QXmppIbbTransferManager.cpp
@@ -0,0 +1,95 @@
+#include "QXmppIbbTransferManager.h"
+#include "QXmppClient.h"
+
+QXmppIbbTransferManager::QXmppIbbTransferManager(QXmppClient* client):
+ m_client(client)
+{
+}
+
+void QXmppIbbTransferManager::teardownIbbTransferManager( const QString &sid )
+{
+ QString id = getIbbTransferJobBySid(sid)->getId();
+ delete m_activeTransfers[id];
+ m_activeTransfers.remove(id);
+}
+
+void QXmppIbbTransferManager::addIbbTransferManager( QXmppIbbTransferJob *mgr )
+{
+ m_activeTransfers[mgr->getId()] = mgr;
+ connect( mgr, SIGNAL(transferCanceled(QString,QString)),
+ this, SIGNAL(byteStreamCanceled(QString,QString)));
+ connect( mgr, SIGNAL(transferFinished(QString,QString)),
+ this, SIGNAL(byteStreamClosed(QString,QString)));
+ connect( mgr, SIGNAL(transferRequested(QString,QString)),
+ this, SIGNAL(byteStreamRequestReceived(QString,QString)));
+ connect( mgr, SIGNAL(transferStarted(QString)),
+ this, SIGNAL(byteStreamOpened(QString)));
+ connect( mgr, SIGNAL(readyForTeardown(QString)),
+ this, SLOT(teardownIbbTransferManager(QString)));
+}
+
+QXmppIbbTransferJob *QXmppIbbTransferManager::getIbbTransferJob( const QString &id )
+{
+ QXmppIbbTransferJob *mgr = m_activeTransfers[id];
+ if( mgr == 0 )
+ {
+ mgr = new QXmppIbbTransferJob(m_client);
+ mgr->setId(id);
+ addIbbTransferManager(mgr);
+ }
+ return mgr;
+}
+
+bool QXmppIbbTransferManager::isIbbTransferJobId( const QString &id )
+{
+ return m_activeTransfers.keys().contains(id);
+}
+
+QXmppIbbTransferJob *QXmppIbbTransferManager::getIbbTransferJobBySid( const QString &sid )
+{
+ foreach( QXmppIbbTransferJob *mgr, m_activeTransfers )
+ {
+ if ( mgr->getSid() == sid )
+ return mgr;
+ }
+
+ return 0;
+}
+
+void QXmppIbbTransferManager::sendByteStreamRequest( const QString &sid, const QString &bareRemoteJid, QIODevice *io)
+{
+
+ QXmppIbbTransferJob *mgr = new QXmppIbbTransferJob(m_client);
+ mgr->setSid( sid );
+ mgr->setRemoteJid( bareRemoteJid ); //FIXME: make like send message
+ mgr->setIoDevice( io );
+ mgr->requestTransfer();
+ addIbbTransferManager( mgr );
+
+}
+
+void QXmppIbbTransferManager::acceptByteStreamRequest( const QString &sid, QIODevice *io )
+{
+ QXmppIbbTransferJob *mgr = getIbbTransferJobBySid(sid);
+ if( mgr == 0 )
+ return;
+
+ mgr->setIoDevice(io);
+ mgr->acceptTransfer();
+}
+
+void QXmppIbbTransferManager::rejectByteStreamRequest( const QString &sid )
+{
+ QXmppIbbTransferJob *mgr = getIbbTransferJobBySid(sid);
+ if( mgr == 0 )
+ return;
+ mgr->cancelTransfer();
+}
+
+void QXmppIbbTransferManager::cancelByteStreamRequest( const QString &sid )
+{
+ QXmppIbbTransferJob *mgr = getIbbTransferJobBySid(sid);
+ if( mgr == 0 )
+ return;
+ mgr->cancelTransfer();
+}
diff --git a/source/QXmppIbbTransferManager.h b/source/QXmppIbbTransferManager.h
new file mode 100644
index 00000000..d812b3fe
--- /dev/null
+++ b/source/QXmppIbbTransferManager.h
@@ -0,0 +1,60 @@
+#ifndef QXMPPIBBTRANSFERMANAGER_H
+#define QXMPPIBBTRANSFERMANAGER_H
+
+#include <QObject>
+#include <QHash>
+#include "QXmppIbbTransferJob.h"
+
+class QXmppClient;
+
+class QXmppIbbTransferManager : public QObject
+{
+public:
+ QXmppIbbTransferManager(QXmppClient* client);
+
+signals:
+ /// Notifies that a XMPP bytestream request has been received. The
+ /// program must either reply with an acceptByteStreamRequest(...) or
+ /// a rejectByteStreamRequest(...) depending on the desired response.
+ void byteStreamRequestReceived( const QString &sid, const QString &remoteJid );
+ /// Notifies that a XMPP bytestream has been closed.
+ void byteStreamClosed( const QString &sid , const QString &reason );
+ /// Notifies that a XMPP bytestream was canceled by the remote peer.
+ /// The reason is given for the cancelation.
+ void byteStreamCanceled( const QString &sid , const QString &reason );
+ /// Notifes that the XMPP bytestream has been opened and the transfer
+ /// has started.
+ void byteStreamOpened( const QString &sid );
+
+public:
+ QXmppIbbTransferJob *getIbbTransferJob( const QString &id );
+ bool isIbbTransferJobId( const QString &id );
+
+public slots:
+ /// Send a request to open a bytestream to a specific jid. Once the
+ /// stream is opened then the data is read from the QIODevice. The
+ /// QIODevice MUST be be open and ready for reading otherwise the
+ /// transfer will fail. When there are no more bytes available to
+ /// send from the QIODevice then the bytestream is closed.
+ void sendByteStreamRequest( const QString &sid, const QString &bareJid, QIODevice *io);
+ /// Accept a bytestream with a specific sid. Data from the remote
+ /// peer is then written to the QIODevice. Therefor the QIODevice must
+ /// be open and ready for writing before this method is called.
+ void acceptByteStreamRequest( const QString &sid, QIODevice *io );
+ /// Rejects a bytestream from a specific sid.
+ void rejectByteStreamRequest( const QString &sid );
+ /// Cacels a currenly connected bytestream with a specific sid.
+ void cancelByteStreamRequest( const QString &sid );
+
+private slots:
+ void addIbbTransferManager( QXmppIbbTransferJob *mgr );
+ void teardownIbbTransferManager( const QString &sid );
+
+private:
+ QXmppIbbTransferJob *getIbbTransferJobBySid( const QString &sid );
+
+ QXmppClient* m_client;
+ QHash<QString, QXmppIbbTransferJob*> m_activeTransfers;
+};
+
+#endif // QXMPPIBBTRANSFERMANAGER_H
diff --git a/source/QXmppStanza.cpp b/source/QXmppStanza.cpp
index 1cfacfb9..c78aeed8 100644
--- a/source/QXmppStanza.cpp
+++ b/source/QXmppStanza.cpp
@@ -28,7 +28,7 @@
#include <QXmlStreamWriter>
-int QXmppStanza::s_uniqeIdNo = 0;
+uint QXmppStanza::s_uniqeIdNo = 0;
QXmppStanza::Error::Error(): m_type(static_cast<QXmppStanza::Error::Type>(-1)),
m_condition(static_cast<QXmppStanza::Error::Condition>(-1)),
diff --git a/source/QXmppStanza.h b/source/QXmppStanza.h
index c5b6cd85..8546aea8 100644
--- a/source/QXmppStanza.h
+++ b/source/QXmppStanza.h
@@ -115,7 +115,7 @@ public:
bool isErrorStanza();
private:
- static int s_uniqeIdNo;
+ static uint s_uniqeIdNo;
QString m_to;
QString m_from;
QString m_id;
diff --git a/source/QXmppStream.cpp b/source/QXmppStream.cpp
index 44d8c5f2..4405e3b4 100644
--- a/source/QXmppStream.cpp
+++ b/source/QXmppStream.cpp
@@ -37,8 +37,12 @@
#include "QXmppVCard.h"
#include "QXmppNonSASLAuth.h"
#include "QXmppInformationRequestResult.h"
+#include "QXmppIbbIqs.h"
+#include "QXmppDataIq.h"
+#include "QXmppIbbTransferManager.h"
#include "QXmppLogger.h"
+
#include <QDomDocument>
#include <QStringList>
#include <QRegExp>
@@ -216,10 +220,11 @@ void QXmppStream::parser(const QByteArray& data)
{
//TODO: Make a login error here.
}
-
while(!nodeRecv.isNull())
{
+
QString ns = nodeRecv.namespaceURI();
+ log("Namespace: " + ns + " Tag: " + nodeRecv.tagName() );
if(ns == ns_stream && nodeRecv.tagName() == "features")
{
bool nonSaslAvailable = nodeRecv.firstChildElement("auth").
@@ -365,12 +370,56 @@ void QXmppStream::parser(const QByteArray& data)
qWarning("QXmppStream: iq type can't be empty");
QXmppIq iqPacket; // to emit
-
QDomElement elemen = nodeRecv.firstChildElement("error");
QXmppStanza::Error error = parseStanzaError(elemen);
+ if( QXmppIbbOpenIq::isIbbOpenIq( nodeRecv ) )
+ {
+ QXmppIbbOpenIq openIqPacket;
+ openIqPacket.parse( nodeRecv );
+
+ QXmppIbbTransferJob *mgr = m_client->getIbbTransferManager()->
+ getIbbTransferJob(openIqPacket.getId());
+ mgr->gotOpen( openIqPacket );
+ }
+ else if( QXmppIbbErrorIq::isIbbErrorIq( nodeRecv ) &&
+ m_client->getIbbTransferManager()->isIbbTransferJobId( id ))
+ {
+ QXmppIbbErrorIq errorIqPacket;
+ errorIqPacket.parse(nodeRecv);
+
+ QXmppIbbTransferJob *mgr = m_client->getIbbTransferManager()->
+ getIbbTransferJob(errorIqPacket.getId());
+ mgr->gotError( errorIqPacket );
+ }
+ else if( QXmppIbbAckIq::isIbbAckIq( nodeRecv ) &&
+ m_client->getIbbTransferManager()->isIbbTransferJobId( id ))
+ {
+ QXmppIbbAckIq ackIqPacket;
+ ackIqPacket.parse(nodeRecv);
+
+ QXmppIbbTransferJob *mgr = m_client->getIbbTransferManager()->getIbbTransferJob(ackIqPacket.getId());
+ mgr->gotAck();
+ }
+ else if( QXmppDataIq::isDataIq( nodeRecv ) &&
+ m_client->getIbbTransferManager()->isIbbTransferJobId( id ))
+ {
+ QXmppDataIq dataIqPacket;
+ dataIqPacket.parse(nodeRecv);
- if(id == m_sessionId)
+ QXmppIbbTransferJob *mgr = m_client->getIbbTransferManager()->getIbbTransferJob(dataIqPacket.getId());
+ mgr->gotData(dataIqPacket);
+ }
+ else if( QXmppIbbCloseIq::isIbbCloseIq( nodeRecv ) &&
+ m_client->getIbbTransferManager()->isIbbTransferJobId( id ))
+ {
+ QXmppIbbCloseIq closeIqPacket;
+ closeIqPacket.parse(nodeRecv);
+
+ QXmppIbbTransferJob *mgr = m_client->getIbbTransferManager()->getIbbTransferJob(closeIqPacket.getId());
+ mgr->gotClose(closeIqPacket);
+ }
+ else if(id == m_sessionId)
{
// get back add configuration whether to send
// roster and intial presence in beginning
diff --git a/source/QXmppUtils.cpp b/source/QXmppUtils.cpp
index 08c1543a..095c746a 100644
--- a/source/QXmppUtils.cpp
+++ b/source/QXmppUtils.cpp
@@ -30,6 +30,7 @@
#include <QBuffer>
#include <QImageReader>
#include <QCryptographicHash>
+#include <QDateTime>
QString jidToResource(const QString& jid)
{
@@ -41,6 +42,18 @@ QString jidToBareJid(const QString& jid)
return jid.left(jid.indexOf(QChar('/')));
}
+QString generateStanzaHash()
+{
+
+ QString somechars = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ QString hashResult;
+ for ( int idx = 0; idx < 10; ++idx )
+ {
+ hashResult += somechars[(qrand() % 61)];
+ }
+ return hashResult;
+}
+
void helperToXmlAddAttribute(QXmlStreamWriter* stream, const QString& name,
const QString& value)
{
diff --git a/source/QXmppUtils.h b/source/QXmppUtils.h
index f9a7cdfd..583d571f 100644
--- a/source/QXmppUtils.h
+++ b/source/QXmppUtils.h
@@ -38,6 +38,7 @@ class QImage;
QString jidToResource(const QString& jid);
QString jidToBareJid(const QString& jid);
+QString generateStanzaHash();
void helperToXmlAddAttribute(QXmlStreamWriter* stream, const QString& name,
const QString& value);
diff --git a/source/source.pro b/source/source.pro
index f6623546..d30fb475 100644
--- a/source/source.pro
+++ b/source/source.pro
@@ -1,16 +1,15 @@
TEMPLATE = lib
QT += network \
xml
-
CONFIG += staticlib \
debug_and_release
-
-CONFIG(debug, debug|release){
- win32:TARGET = QXmppClient_d
- !win32:TARGET = debug\QXmppClient_d
-}else{
- win32:TARGET = QXmppClient
- !win32:TARGET = release\QXmppClient
+CONFIG(debug, debug|release) {
+ win32:TARGET = QXmppClient_d
+ !win32:TARGET = debug/QXmppClient_d
+}
+else {
+ win32:TARGET = QXmppClient
+ !win32:TARGET = release/QXmppClient
}
# Header files
@@ -33,7 +32,11 @@ HEADERS += QXmppUtils.h \
QXmppVCardManager.h \
QXmppVCard.h \
QXmppNonSASLAuth.h \
- QXmppInformationRequestResult.h
+ QXmppInformationRequestResult.h \
+ QXmppDataIq.h \
+ QXmppIbbIqs.h \
+ QXmppIbbTransferJob.h \
+ QXmppIbbTransferManager.h
# Source files
SOURCES += QXmppUtils.cpp \
@@ -55,4 +58,8 @@ SOURCES += QXmppUtils.cpp \
QXmppVCardManager.cpp \
QXmppVCard.cpp \
QXmppNonSASLAuth.cpp \
- QXmppInformationRequestResult.cpp
+ QXmppInformationRequestResult.cpp \
+ QXmppDataIq.cpp \
+ QXmppIbbIqs.cpp \
+ QXmppIbbTransferJob.cpp \
+ QXmppIbbTransferManager.cpp