diff options
| author | Manjeet Dahiya <manjeetdahiya@gmail.com> | 2009-10-27 12:04:03 +0000 |
|---|---|---|
| committer | Manjeet Dahiya <manjeetdahiya@gmail.com> | 2009-10-27 12:04:03 +0000 |
| commit | 10c093a617929db5c6b201dbf03d6070b12b36b4 (patch) | |
| tree | d9b1c4507fdb1969c3225f27b4632258c4916dc0 /source | |
| parent | 239b2b15c3cfd9e4d7cc085ed31645d6ae6942ee (diff) | |
| download | qxmpp-10c093a617929db5c6b201dbf03d6070b12b36b4.tar.gz | |
Issue 15: Implement XEP-0047
Diffstat (limited to 'source')
| -rw-r--r-- | source/QXmppBind.cpp | 3 | ||||
| -rw-r--r-- | source/QXmppClient.cpp | 10 | ||||
| -rw-r--r-- | source/QXmppClient.h | 3 | ||||
| -rw-r--r-- | source/QXmppConfiguration.h | 6 | ||||
| -rw-r--r-- | source/QXmppDataIq.cpp | 69 | ||||
| -rw-r--r-- | source/QXmppDataIq.h | 30 | ||||
| -rw-r--r-- | source/QXmppIbbIqs.cpp | 202 | ||||
| -rw-r--r-- | source/QXmppIbbIqs.h | 70 | ||||
| -rw-r--r-- | source/QXmppIbbTransferJob.cpp | 230 | ||||
| -rw-r--r-- | source/QXmppIbbTransferJob.h | 66 | ||||
| -rw-r--r-- | source/QXmppIbbTransferManager.cpp | 95 | ||||
| -rw-r--r-- | source/QXmppIbbTransferManager.h | 60 | ||||
| -rw-r--r-- | source/QXmppStanza.cpp | 2 | ||||
| -rw-r--r-- | source/QXmppStanza.h | 2 | ||||
| -rw-r--r-- | source/QXmppStream.cpp | 55 | ||||
| -rw-r--r-- | source/QXmppUtils.cpp | 13 | ||||
| -rw-r--r-- | source/QXmppUtils.h | 1 | ||||
| -rw-r--r-- | source/source.pro | 27 |
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 |
