From 10c093a617929db5c6b201dbf03d6070b12b36b4 Mon Sep 17 00:00:00 2001 From: Manjeet Dahiya Date: Tue, 27 Oct 2009 12:04:03 +0000 Subject: Issue 15: Implement XEP-0047 --- source/QXmppBind.cpp | 3 - source/QXmppClient.cpp | 10 +- source/QXmppClient.h | 3 + source/QXmppConfiguration.h | 6 +- source/QXmppDataIq.cpp | 69 +++++++++++ source/QXmppDataIq.h | 30 +++++ source/QXmppIbbIqs.cpp | 202 ++++++++++++++++++++++++++++++++ source/QXmppIbbIqs.h | 70 +++++++++++ source/QXmppIbbTransferJob.cpp | 230 +++++++++++++++++++++++++++++++++++++ source/QXmppIbbTransferJob.h | 66 +++++++++++ source/QXmppIbbTransferManager.cpp | 95 +++++++++++++++ source/QXmppIbbTransferManager.h | 60 ++++++++++ source/QXmppStanza.cpp | 2 +- source/QXmppStanza.h | 2 +- source/QXmppStream.cpp | 55 ++++++++- source/QXmppUtils.cpp | 13 +++ source/QXmppUtils.h | 1 + source/source.pro | 27 +++-- 18 files changed, 921 insertions(+), 23 deletions(-) create mode 100644 source/QXmppDataIq.cpp create mode 100644 source/QXmppDataIq.h create mode 100644 source/QXmppIbbIqs.cpp create mode 100644 source/QXmppIbbIqs.h create mode 100644 source/QXmppIbbTransferJob.cpp create mode 100644 source/QXmppIbbTransferJob.h create mode 100644 source/QXmppIbbTransferManager.cpp create mode 100644 source/QXmppIbbTransferManager.h (limited to 'source') 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 +#include + +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 +#include + +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 +#include +#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 +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 +#include +#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 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 -int QXmppStanza::s_uniqeIdNo = 0; +uint QXmppStanza::s_uniqeIdNo = 0; QXmppStanza::Error::Error(): m_type(static_cast(-1)), m_condition(static_cast(-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 #include #include @@ -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 #include #include +#include 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 -- cgit v1.2.3