Projects
home:pansenmann:branches:Multimedia
jreen
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 2
View file
jreen.spec
Changed
@@ -1,7 +1,7 @@ # vim: set sw=4 ts=4 et nu: Name: jreen -Version: 1.0.3 +Version: 1.1.0 %define soname 1 Release: 0.pm.1 Summary: Qt Jabber/XMPP library
View file
libjreen-1.0.3.tar.bz2/src/gui
Deleted
-(directory)
View file
libjreen-1.0.3.tar.bz2/src/multimediadata.cpp
Deleted
@@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Jreen -** -** Copyright © 2011 Aleksey Sidorov <gorthauer87@yandex.ru> -** -***************************************************************************** -** -** $JREEN_BEGIN_LICENSE$ -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -** See the GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see http://www.gnu.org/licenses/. -** $JREEN_END_LICENSE$ -** -****************************************************************************/ - -#include "multimediadata.h" - -namespace Jreen -{ - -class MultimediaDataPrivate : public QSharedData -{ -public: - MultimediaDataPrivate() : QSharedData() {} - MultimediaDataPrivate(const MultimediaDataPrivate &other) : - QSharedData(other), - type(other.type), - data(other.data), - attributes(other.attributes) - { - } - MultimediaData::Type type; - QVariantList data; - QVariantMap attributes; -}; - -MultimediaData::MultimediaData(Type type,const QVariantList &data,const QVariantMap &attributes) : - d_ptr(new MultimediaDataPrivate) -{ - d_ptr->type = type; - d_ptr->data = data; - d_ptr->attributes = attributes; -} - -MultimediaData::MultimediaData(const MultimediaData &other) : - d_ptr(other.d_ptr) -{ -} - -MultimediaData::~MultimediaData() -{ - -} - -MultimediaData &MultimediaData::operator =(const MultimediaData &o) -{ - d_ptr = o.d_ptr; - return *this; -} - -QVariantMap MultimediaData::attributes() const -{ - return d_ptr->attributes; -} -QVariantList MultimediaData::data() const -{ - return d_ptr->data; -} -void MultimediaData::setData(const QVariantList &data) -{ - d_ptr->data = data; -} - -void MultimediaData::setAttributes(const QVariantMap &attributes) -{ - d_ptr->attributes = attributes; -} - -} // namespace Jreen
View file
libjreen-1.0.3.tar.bz2/src/multimediadata.h
Deleted
@@ -1,59 +0,0 @@ -/**************************************************************************** -** -** Jreen -** -** Copyright © 2011 Aleksey Sidorov <gorthauer87@yandex.ru> -** -***************************************************************************** -** -** $JREEN_BEGIN_LICENSE$ -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -** See the GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see http://www.gnu.org/licenses/. -** $JREEN_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MULTIMEDIADATA_H -#define MULTIMEDIADATA_H -#include <QVariantMap> -#include "stanzaextension.h" - -namespace Jreen -{ - -// XEP-0221 -// http://xmpp.org/extensions/xep-0221.html -class MultimediaDataPrivate; -class JREEN_EXPORT MultimediaData -{ -public: - enum Type - { - Audio, - Image - }; - MultimediaData(Type type,const QVariantList &data,const QVariantMap &attributes = QVariantMap()); - MultimediaData(const MultimediaData &other); - ~MultimediaData(); - MultimediaData &operator =(const MultimediaData &o); - QVariantMap attributes() const; - QVariantList data() const; - void setData(const QVariantList &data); - void setAttributes(const QVariantMap &attributes); -private: - QSharedDataPointer<MultimediaDataPrivate> d_ptr; - friend class MultimediaDataPrivate; -}; - -} // namespace Jreen -#endif // MULTIMEDIADATA_H
View file
libjreen-1.0.3.tar.bz2/src/multimediadatafactory.cpp
Deleted
@@ -1,113 +0,0 @@ -/**************************************************************************** -** -** Jreen -** -** Copyright © 2011 Aleksey Sidorov <gorthauer87@yandex.ru> -** -***************************************************************************** -** -** $JREEN_BEGIN_LICENSE$ -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -** See the GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see http://www.gnu.org/licenses/. -** $JREEN_END_LICENSE$ -** -****************************************************************************/ - -#include "multimediadatafactory_p.h" -#define NS_MULTIMEDIA_DATA QLatin1String("urn:xmpp:media-element") -#include <QLatin1String> -#include <QXmlStreamWriter> -#include <QStringList> - -namespace Jreen { - -MultimediaDataFactory::MultimediaDataFactory() -{ -} - -MultimediaDataFactory::~MultimediaDataFactory() -{ - -} - -QStringList MultimediaDataFactory::features() const -{ - return QStringList(NS_MULTIMEDIA_DATA); -} -bool MultimediaDataFactory::canParse(const QStringRef &name, const QStringRef &uri, - const QXmlStreamAttributes &attributes) -{ - Q_UNUSED(attributes); - return name == QLatin1String("media") && uri == NS_MULTIMEDIA_DATA; -} - -void MultimediaDataFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, - const QXmlStreamAttributes &attributes) -{ - Q_UNUSED(name); - Q_UNUSED(attributes); - Q_UNUSED(uri); - m_depth++; - if(m_depth == 1) { - foreach(const QXmlStreamAttribute &attribute,attributes) { - m_attributes.insert(attribute.name().toString(), - attribute.value().toString()); - } - } else if(m_depth == 2) { - m_currentDataItem.clear(); - m_currentDataItem.insert("type",attributes.value("type").toString()); - } -} - -void MultimediaDataFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) -{ - Q_UNUSED(name); - Q_UNUSED(uri); - if(m_depth == 2) - m_data.append(m_currentDataItem); - m_depth--; -} - -void MultimediaDataFactory::handleCharacterData(const QStringRef &text) -{ - if(m_depth == 2) - m_currentDataItem.insert("uri",text.toString()); -} - -void MultimediaDataFactory::serialize(const MultimediaData &media, QXmlStreamWriter *writer) -{ - writer->writeStartElement(QLatin1String("media")); - writer->writeDefaultNamespace(NS_MULTIMEDIA_DATA); - - QVariantMap attributes = media.attributes(); - QVariantMap::const_iterator it = attributes.constBegin(); - while(it != attributes.constEnd()) { - writer->writeAttribute(it.key(),it.value().toString()); - it++; - } - foreach(QVariant item,media.data()) { - QVariantMap map = item.toMap(); - writer->writeStartElement(QLatin1String("uri")); - writer->writeAttribute(QLatin1String("type"),map.value("type").toString()); - writer->writeCharacters(map.value("uri").toString()); - writer->writeEndElement(); - } - writer->writeEndElement(); -} - -MultimediaData MultimediaDataFactory::create() -{ - return MultimediaData(m_type,m_data,m_attributes); -} - -} // namespace Jreen
View file
libjreen-1.0.3.tar.bz2/src/multimediadatafactory_p.h
Deleted
@@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Jreen -** -** Copyright © 2011 Aleksey Sidorov <gorthauer87@yandex.ru> -** -***************************************************************************** -** -** $JREEN_BEGIN_LICENSE$ -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -** See the GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see http://www.gnu.org/licenses/. -** $JREEN_END_LICENSE$ -** -****************************************************************************/ - -#ifndef MULTIMEDIADATAFACTORY_H -#define MULTIMEDIADATAFACTORY_P_H -#include "multimediadata.h" - -namespace Jreen { - -class MultimediaDataFactory : public XmlStreamParser -{ -public: - MultimediaDataFactory(); - virtual ~MultimediaDataFactory(); - QStringList features() const; - bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); - void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); - void handleEndElement(const QStringRef &name, const QStringRef &uri); - void handleCharacterData(const QStringRef &text); - void serialize(const MultimediaData &media, QXmlStreamWriter *writer); - MultimediaData create(); -private: - QVariantMap m_attributes; - QVariantList m_data; - QVariantMap m_currentDataItem; - int m_depth; - MultimediaData::Type m_type; -}; - -} // namespace Jreen - -#endif // MULTIMEDIADATAFACTORY_H
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport
Added
+(directory)
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/bsocket.cpp
Added
@@ -0,0 +1,399 @@ +/* + * bsocket.cpp - QSocket wrapper based on Bytestream with SRV DNS support + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <QTcpSocket> +#include <QHostAddress> +#include <QMetaType> + +#include "bsocket.h" + +//#include "safedelete.h" + +//#define BS_DEBUG + +#ifdef BS_DEBUG +#include <stdio.h> +#endif + +#define READBUFSIZE 65536 + +// CS_NAMESPACE_BEGIN + +class QTcpSocketSignalRelay : public QObject +{ + Q_OBJECT +public: + QTcpSocketSignalRelay(QTcpSocket *sock, QObject *parent = 0) + :QObject(parent) + { + qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError"); + connect(sock, SIGNAL(hostFound()), SLOT(sock_hostFound()), Qt::QueuedConnection); + connect(sock, SIGNAL(connected()), SLOT(sock_connected()), Qt::QueuedConnection); + connect(sock, SIGNAL(disconnected()), SLOT(sock_disconnected()), Qt::QueuedConnection); + connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()), Qt::QueuedConnection); + connect(sock, SIGNAL(bytesWritten(qint64)), SLOT(sock_bytesWritten(qint64)), Qt::QueuedConnection); + connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(sock_error(QAbstractSocket::SocketError)), Qt::QueuedConnection); + } + +signals: + void hostFound(); + void connected(); + void disconnected(); + void readyRead(); + void bytesWritten(qint64); + void error(QAbstractSocket::SocketError); + +public slots: + void sock_hostFound() + { + emit hostFound(); + } + + void sock_connected() + { + emit connected(); + } + + void sock_disconnected() + { + emit disconnected(); + } + + void sock_readyRead() + { + emit readyRead(); + } + + void sock_bytesWritten(qint64 x) + { + emit bytesWritten(x); + } + + void sock_error(QAbstractSocket::SocketError x) + { + emit error(x); + } +}; + +class BSocket::Private +{ +public: + Private(BSocket *_q) + { + qsock = 0; + qsock_relay = 0; + } + + QTcpSocket *qsock; + QTcpSocketSignalRelay *qsock_relay; + int state; + + QString host; + int port; + QHostAddress addr; + //SafeDelete sd; +}; + +BSocket::BSocket(QObject *parent) +:ByteStream(parent) +{ + d = new Private(this); + + reset(); +} + +BSocket::~BSocket() +{ + reset(true); + delete d; +} + +void BSocket::reset(bool clear) +{ + if(d->qsock) { + delete d->qsock_relay; + d->qsock_relay = 0; + + /*d->qsock->disconnect(this); + + if(!clear && d->qsock->isOpen() && d->qsock->isValid()) {*/ + // move remaining into the local queue + QByteArray block(d->qsock->bytesAvailable(), 0); + d->qsock->read(block.data(), block.size()); + appendRead(block); + //} + + //d->sd.deleteLater(d->qsock); + d->qsock->deleteLater(); + d->qsock = 0; + } + else { + if(clear) + clearReadBuffer(); + } + + d->state = Idle; + d->addr = QHostAddress(); +} + +void BSocket::ensureSocket() +{ + if(!d->qsock) { + d->qsock = new QTcpSocket(this); +#if QT_VERSION >= 0x030200 + d->qsock->setReadBufferSize(READBUFSIZE); +#endif + d->qsock_relay = new QTcpSocketSignalRelay(d->qsock, this); + connect(d->qsock_relay, SIGNAL(hostFound()), SLOT(qs_hostFound())); + connect(d->qsock_relay, SIGNAL(connected()), SLOT(qs_connected())); + connect(d->qsock_relay, SIGNAL(disconnected()), SLOT(qs_closed())); + connect(d->qsock_relay, SIGNAL(readyRead()), SLOT(qs_readyRead())); + connect(d->qsock_relay, SIGNAL(bytesWritten(qint64)), SLOT(qs_bytesWritten(qint64))); + connect(d->qsock_relay, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(qs_error(QAbstractSocket::SocketError))); + } +} + +void BSocket::connectToHost(const QString &host, quint16 port) +{ + reset(true); + d->host = host; + d->port = port; + d->state = HostLookup; + do_connect(); +} + +void BSocket::connectToHost(const QHostAddress &addr, quint16 port) +{ + reset(true); + d->host = addr.toString(); + d->addr = addr; + d->port = port; + d->state = Connecting; + do_connect(); +} + +int BSocket::socket() const +{ + if(d->qsock) + return d->qsock->socketDescriptor(); + else + return -1; +} + +void BSocket::setSocket(int s) +{ + reset(true); + ensureSocket(); + d->state = Connected; + d->qsock->setSocketDescriptor(s); +} + +int BSocket::state() const +{ + return d->state; +} + +bool BSocket::isOpen() const +{ + if(d->state == Connected) + return true; + else + return false; +} + +void BSocket::close() +{ + if(d->state == Idle) + return; + + if(d->qsock) { + d->qsock->close(); + d->state = Closing; + if(d->qsock->bytesToWrite() == 0) + reset(); + } + else { + reset(); + } +} + +void BSocket::write(const QByteArray &a) +{ + if(d->state != Connected) + return; +#ifdef BS_DEBUG + QString s = QString::fromUtf8(a); + fprintf(stderr, "BSocket: writing %d: {%s}\n", a.size(), s.latin1()); +#endif + d->qsock->write(a.data(), a.size()); +} + +QByteArray BSocket::read(int bytes) +{ + QByteArray block; + if(d->qsock) { + int max = bytesAvailable(); + if(bytes <= 0 || bytes > max) + bytes = max; + block.resize(bytes); + d->qsock->read(block.data(), block.size()); + } + else + block = ByteStream::read(bytes); + +#ifdef BS_DEBUG + QString s = QString::fromUtf8(block); + fprintf(stderr, "BSocket: read %d: {%s}\n", block.size(), s.latin1()); +#endif + return block; +} + +int BSocket::bytesAvailable() const +{ + if(d->qsock) + return d->qsock->bytesAvailable(); + else + return ByteStream::bytesAvailable(); +} + +int BSocket::bytesToWrite() const +{ + if(!d->qsock) + return 0; + return d->qsock->bytesToWrite(); +} + +QHostAddress BSocket::address() const +{ + if(d->qsock) + return d->qsock->localAddress(); + else + return QHostAddress(); +} + +quint16 BSocket::port() const +{ + if(d->qsock) + return d->qsock->localPort(); + else + return 0; +} + +QHostAddress BSocket::peerAddress() const +{ + if(d->qsock) + return d->qsock->peerAddress(); + else + return QHostAddress(); +} + +quint16 BSocket::peerPort() const +{ + if(d->qsock) + return d->qsock->peerPort(); + else + return 0; +} + +void BSocket::do_connect() +{ +#ifdef BS_DEBUG + fprintf(stderr, "BSocket: Connecting to %s:%d\n", d->host.latin1(), d->port); +#endif + ensureSocket(); + if(!d->addr.isNull()) + d->qsock->connectToHost(d->addr, d->port); + else + d->qsock->connectToHost(d->host, d->port); +} + +void BSocket::qs_hostFound() +{ + //SafeDeleteLock s(&d->sd); +} + +void BSocket::qs_connected() +{ + d->state = Connected; +#ifdef BS_DEBUG + fprintf(stderr, "BSocket: Connected.\n"); +#endif + //SafeDeleteLock s(&d->sd); + connected(); +} + +void BSocket::qs_closed() +{ + if(d->state == Closing) + { +#ifdef BS_DEBUG + fprintf(stderr, "BSocket: Delayed Close Finished.\n"); +#endif + //SafeDeleteLock s(&d->sd); + reset(); + delayedCloseFinished(); + } +} + +void BSocket::qs_readyRead() +{ + //SafeDeleteLock s(&d->sd); + readyRead(); +} + +void BSocket::qs_bytesWritten(qint64 x64) +{ + int x = x64; +#ifdef BS_DEBUG + fprintf(stderr, "BSocket: BytesWritten %d.\n", x); +#endif + //SafeDeleteLock s(&d->sd); + bytesWritten(x); +} + +void BSocket::qs_error(QAbstractSocket::SocketError x) +{ + if(x == QTcpSocket::RemoteHostClosedError) { +#ifdef BS_DEBUG + fprintf(stderr, "BSocket: Connection Closed.\n"); +#endif + //SafeDeleteLock s(&d->sd); + reset(); + connectionClosed(); + return; + } + +#ifdef BS_DEBUG + fprintf(stderr, "BSocket: Error.\n"); +#endif + //SafeDeleteLock s(&d->sd); + + reset(); + if(x == QTcpSocket::ConnectionRefusedError) + error(ErrConnectionRefused); + else if(x == QTcpSocket::HostNotFoundError) + error(ErrHostNotFound); + else + error(ErrRead); +} + +#include "bsocket.moc" + +// CS_NAMESPACE_END
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/bsocket.h
Added
@@ -0,0 +1,88 @@ +/* + * bsocket.h - QSocket wrapper based on Bytestream with SRV DNS support + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef CS_BSOCKET_H +#define CS_BSOCKET_H + +#include <QAbstractSocket> + +#include "bytestream.h" + +class QString; +class QObject; +class QByteArray; + +// CS_NAMESPACE_BEGIN + +class BSocket : public ByteStream +{ + Q_OBJECT +public: + enum Error { ErrConnectionRefused = ErrCustom, ErrHostNotFound }; + enum State { Idle, HostLookup, Connecting, Connected, Closing }; + BSocket(QObject *parent=0); + ~BSocket(); + + void connectToHost(const QString &host, quint16 port); + void connectToHost(const QHostAddress &addr, quint16 port); + int socket() const; + void setSocket(int); + int state() const; + + // from ByteStream + bool isOpen() const; + void close(); + void write(const QByteArray &); + QByteArray read(int bytes=0); + int bytesAvailable() const; + int bytesToWrite() const; + + // local + QHostAddress address() const; + quint16 port() const; + + // remote + QHostAddress peerAddress() const; + quint16 peerPort() const; + +signals: + void hostFound(); + void connected(); + +private slots: + void qs_hostFound(); + void qs_connected(); + void qs_closed(); + void qs_readyRead(); + void qs_bytesWritten(qint64); + void qs_error(QAbstractSocket::SocketError); + void do_connect(); + +private: + class Private; + Private *d; + + void reset(bool clear=false); + void ensureSocket(); +}; + +// CS_NAMESPACE_END + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/bytestream.cpp
Added
@@ -0,0 +1,259 @@ +/* + * bytestream.cpp - base class for bytestreams + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "bytestream.h" +#include <QByteArray> + +// CS_NAMESPACE_BEGIN + +//! \class ByteStream bytestream.h +//! \brief Base class for "bytestreams" +//! +//! This class provides a basic framework for a "bytestream", here defined +//! as a bi-directional, asynchronous pipe of data. It can be used to create +//! several different kinds of bytestream-applications, such as a console or +//! TCP connection, or something more abstract like a security layer or tunnel, +//! all with the same interface. The provided functions make creating such +//! classes simpler. ByteStream is a pure-virtual class, so you do not use it +//! on its own, but instead through a subclass such as \a BSocket. +//! +//! The signals connectionClosed(), delayedCloseFinished(), readyRead(), +//! bytesWritten(), and error() serve the exact same function as those from +//! <A HREF="http://doc.trolltech.com/3.1/qsocket.html">QSocket</A>. +//! +//! The simplest way to create a ByteStream is to reimplement isOpen(), close(), +//! and tryWrite(). Call appendRead() whenever you want to make data available for +//! reading. ByteStream will take care of the buffers with regards to the caller, +//! and will call tryWrite() when the write buffer gains data. It will be your +//! job to call tryWrite() whenever it is acceptable to write more data to +//! the underlying system. +//! +//! If you need more advanced control, reimplement read(), write(), bytesAvailable(), +//! and/or bytesToWrite() as necessary. +//! +//! Use appendRead(), appendWrite(), takeRead(), and takeWrite() to modify the +//! buffers. If you have more advanced requirements, the buffers can be accessed +//! directly with readBuf() and writeBuf(). +//! +//! Also available are the static convenience functions ByteStream::appendArray() +//! and ByteStream::takeArray(), which make dealing with byte queues very easy. + +class ByteStream::Private +{ +public: + Private() {} + + QByteArray readBuf, writeBuf; +}; + +//! +//! Constructs a ByteStream object with parent \a parent. +ByteStream::ByteStream(QObject *parent) +:QObject(parent) +{ + d = new Private; +} + +//! +//! Destroys the object and frees allocated resources. +ByteStream::~ByteStream() +{ + delete d; +} + +//! +//! Returns TRUE if the stream is open, meaning that you can write to it. +bool ByteStream::isOpen() const +{ + return false; +} + +//! +//! Closes the stream. If there is data in the write buffer then it will be +//! written before actually closing the stream. Once all data has been written, +//! the delayedCloseFinished() signal will be emitted. +//! \sa delayedCloseFinished() +void ByteStream::close() +{ +} + +//! +//! Writes array \a a to the stream. +void ByteStream::write(const QByteArray &a) +{ + if(!isOpen()) + return; + + bool doWrite = bytesToWrite() == 0 ? true: false; + appendWrite(a); + if(doWrite) + tryWrite(); +} + +//! +//! Reads bytes \a bytes of data from the stream and returns them as an array. If \a bytes is 0, then +//! \a read will return all available data. +QByteArray ByteStream::read(int bytes) +{ + return takeRead(bytes); +} + +//! +//! Returns the number of bytes available for reading. +int ByteStream::bytesAvailable() const +{ + return d->readBuf.size(); +} + +//! +//! Returns the number of bytes that are waiting to be written. +int ByteStream::bytesToWrite() const +{ + return d->writeBuf.size(); +} + +//! +//! Clears the read buffer. +void ByteStream::clearReadBuffer() +{ + d->readBuf.resize(0); +} + +//! +//! Clears the write buffer. +void ByteStream::clearWriteBuffer() +{ + d->writeBuf.resize(0); +} + +//! +//! Appends \a block to the end of the read buffer. +void ByteStream::appendRead(const QByteArray &block) +{ + appendArray(&d->readBuf, block); +} + +//! +//! Appends \a block to the end of the write buffer. +void ByteStream::appendWrite(const QByteArray &block) +{ + appendArray(&d->writeBuf, block); +} + +//! +//! Returns \a size bytes from the start of the read buffer. +//! If \a size is 0, then all available data will be returned. +//! If \a del is TRUE, then the bytes are also removed. +QByteArray ByteStream::takeRead(int size, bool del) +{ + return takeArray(&d->readBuf, size, del); +} + +//! +//! Returns \a size bytes from the start of the write buffer. +//! If \a size is 0, then all available data will be returned. +//! If \a del is TRUE, then the bytes are also removed. +QByteArray ByteStream::takeWrite(int size, bool del) +{ + return takeArray(&d->writeBuf, size, del); +} + +//! +//! Returns a reference to the read buffer. +QByteArray & ByteStream::readBuf() +{ + return d->readBuf; +} + +//! +//! Returns a reference to the write buffer. +QByteArray & ByteStream::writeBuf() +{ + return d->writeBuf; +} + +//! +//! Attempts to try and write some bytes from the write buffer, and returns the number +//! successfully written or -1 on error. The default implementation returns -1. +int ByteStream::tryWrite() +{ + return -1; +} + +//! +//! Append array \a b to the end of the array pointed to by \a a. +void ByteStream::appendArray(QByteArray *a, const QByteArray &b) +{ + int oldsize = a->size(); + a->resize(oldsize + b.size()); + memcpy(a->data() + oldsize, b.data(), b.size()); +} + +//! +//! Returns \a size bytes from the start of the array pointed to by \a from. +//! If \a size is 0, then all available data will be returned. +//! If \a del is TRUE, then the bytes are also removed. +QByteArray ByteStream::takeArray(QByteArray *from, int size, bool del) +{ + QByteArray a; + if(size == 0) { + a = *from; + if(del) + from->resize(0); + } + else { + if(size > (int)from->size()) + size = from->size(); + a.resize(size); + char *r = from->data(); + memcpy(a.data(), r, size); + if(del) { + int newsize = from->size()-size; + memmove(r, r+size, newsize); + from->resize(newsize); + } + } + return a; +} + void connectionClosed(); + void delayedCloseFinished(); + void readyRead(); + void bytesWritten(int); + void error(int); + +//! \fn void ByteStream::connectionClosed() +//! This signal is emitted when the remote end of the stream closes. + +//! \fn void ByteStream::delayedCloseFinished() +//! This signal is emitted when all pending data has been written to the stream +//! after an attempt to close. + +//! \fn void ByteStream::readyRead() +//! This signal is emitted when data is available to be read. + +//! \fn void ByteStream::bytesWritten(int x); +//! This signal is emitted when data has been successfully written to the stream. +//! \a x is the number of bytes written. + +//! \fn void ByteStream::error(int code) +//! This signal is emitted when an error occurs in the stream. The reason for +//! error is indicated by \a code. + +// CS_NAMESPACE_END
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/bytestream.h
Added
@@ -0,0 +1,76 @@ +/* + * bytestream.h - base class for bytestreams + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef CS_BYTESTREAM_H +#define CS_BYTESTREAM_H + +#include <QObject> +#include <QByteArray> + +// CS_NAMESPACE_BEGIN + +// CS_EXPORT_BEGIN +class ByteStream : public QObject +{ + Q_OBJECT +public: + enum Error { ErrRead, ErrWrite, ErrCustom = 10 }; + ByteStream(QObject *parent=0); + virtual ~ByteStream()=0; + + virtual bool isOpen() const; + virtual void close(); + virtual void write(const QByteArray &); + virtual QByteArray read(int bytes=0); + virtual int bytesAvailable() const; + virtual int bytesToWrite() const; + + static void appendArray(QByteArray *a, const QByteArray &b); + static QByteArray takeArray(QByteArray *from, int size=0, bool del=true); + +signals: + void connectionClosed(); + void delayedCloseFinished(); + void readyRead(); + void bytesWritten(int); + void error(int); + +protected: + void clearReadBuffer(); + void clearWriteBuffer(); + void appendRead(const QByteArray &); + void appendWrite(const QByteArray &); + QByteArray takeRead(int size=0, bool del=true); + QByteArray takeWrite(int size=0, bool del=true); + QByteArray & readBuf(); + QByteArray & writeBuf(); + virtual int tryWrite(); + +private: +//! \if _hide_doc_ + class Private; + Private *d; +//! \endif +}; +// CS_EXPORT_END + +// CS_NAMESPACE_END + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/httpconnect.cpp
Added
@@ -0,0 +1,387 @@ +/* + * httpconnect.cpp - HTTP "CONNECT" proxy + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "httpconnect.h" + +#include <qstringlist.h> +#include <QByteArray> +#include "bsocket.h" +#include <QtCrypto> + +//#define PROX_DEBUG + +#ifdef PROX_DEBUG +#include <stdio.h> +#endif + +// CS_NAMESPACE_BEGIN + +#ifdef PROX_DEBUG +QString escapeOutput(const QByteArray &in) +{ + QString out; + for(int n = 0; n < in.size(); ++n) { + if(inn == '\\') { + out += QString("\\\\"); + } + else if(inn >= 32 && inn < 127) { + out += QChar::fromLatin1(inn); + } + else { + out += QString().sprintf("\\x%02x", (unsigned char)inn); + } + } + return out; +} +#endif + +static QString extractLine(QByteArray *buf, bool *found) +{ + // Scan for newline + int index = buf->indexOf ("\r\n"); + if (index == -1) { + // Newline not found + if (found) + *found = false; + return ""; + } + else { + // Found newline + QString s = QString::fromAscii(buf->left(index)); + buf->remove(0, index + 2); + + if (found) + *found = true; + return s; + } +} + +static bool extractMainHeader(const QString &line, QString *proto, int *code, QString *msg) +{ + int n = line.indexOf(' '); + if(n == -1) + return false; + if(proto) + *proto = line.mid(0, n); + ++n; + int n2 = line.indexOf(' ', n); + if(n2 == -1) + return false; + if(code) + *code = line.mid(n, n2-n).toInt(); + n = n2+1; + if(msg) + *msg = line.mid(n); + return true; +} + +class HttpConnect::Private +{ +public: + Private(HttpConnect *_q) : + sock(_q) + { + } + + BSocket sock; + QString host; + int port; + QString user, pass; + QString real_host; + int real_port; + + QByteArray recvBuf; + + bool inHeader; + QStringList headerLines; + + int toWrite; + bool active; +}; + +HttpConnect::HttpConnect(QObject *parent) +:ByteStream(parent) +{ + d = new Private(this); + connect(&d->sock, SIGNAL(connected()), SLOT(sock_connected())); + connect(&d->sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed())); + connect(&d->sock, SIGNAL(delayedCloseFinished()), SLOT(sock_delayedCloseFinished())); + connect(&d->sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); + connect(&d->sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int))); + connect(&d->sock, SIGNAL(error(int)), SLOT(sock_error(int))); + + reset(true); +} + +HttpConnect::~HttpConnect() +{ + reset(true); + delete d; +} + +void HttpConnect::reset(bool clear) +{ + if(d->sock.state() != BSocket::Idle) + d->sock.close(); + if(clear) { + clearReadBuffer(); + d->recvBuf.resize(0); + } + d->active = false; +} + +void HttpConnect::setAuth(const QString &user, const QString &pass) +{ + d->user = user; + d->pass = pass; +} + +void HttpConnect::connectToHost(const QString &proxyHost, int proxyPort, const QString &host, int port) +{ + reset(true); + + d->host = proxyHost; + d->port = proxyPort; + d->real_host = host; + d->real_port = port; + +#ifdef PROX_DEBUG + fprintf(stderr, "HttpConnect: Connecting to %s:%d", qPrintable(proxyHost), proxyPort); + if(d->user.isEmpty()) + fprintf(stderr, "\n"); + else + fprintf(stderr, ", auth {%s,%s}\n", qPrintable(d->user), qPrintable(d->pass)); +#endif + d->sock.connectToHost(d->host, d->port); +} + +bool HttpConnect::isOpen() const +{ + return d->active; +} + +void HttpConnect::close() +{ + d->sock.close(); + if(d->sock.bytesToWrite() == 0) + reset(); +} + +void HttpConnect::write(const QByteArray &buf) +{ + if(d->active) + d->sock.write(buf); +} + +QByteArray HttpConnect::read(int bytes) +{ + return ByteStream::read(bytes); +} + +int HttpConnect::bytesAvailable() const +{ + return ByteStream::bytesAvailable(); +} + +int HttpConnect::bytesToWrite() const +{ + if(d->active) + return d->sock.bytesToWrite(); + else + return 0; +} + +void HttpConnect::sock_connected() +{ +#ifdef PROX_DEBUG + fprintf(stderr, "HttpConnect: Connected\n"); +#endif + d->inHeader = true; + d->headerLines.clear(); + + // connected, now send the request + QString s; + s += QString("CONNECT ") + d->real_host + ':' + QString::number(d->real_port) + " HTTP/1.0\r\n"; + if(!d->user.isEmpty()) { + QString str = d->user + ':' + d->pass; + s += QString("Proxy-Authorization: Basic ") + QCA::Base64().encodeString(str) + "\r\n"; + } + s += "Pragma: no-cache\r\n"; + s += "\r\n"; + + QByteArray block = s.toUtf8(); +#ifdef PROX_DEBUG + fprintf(stderr, "HttpConnect: writing: {%s}\n", qPrintable(escapeOutput(block))); +#endif + d->toWrite = block.size(); + d->sock.write(block); +} + +void HttpConnect::sock_connectionClosed() +{ + if(d->active) { + reset(); + connectionClosed(); + } + else { + error(ErrProxyNeg); + } +} + +void HttpConnect::sock_delayedCloseFinished() +{ + if(d->active) { + reset(); + delayedCloseFinished(); + } +} + +void HttpConnect::sock_readyRead() +{ + QByteArray block = d->sock.read(); + + if(!d->active) { + ByteStream::appendArray(&d->recvBuf, block); + + if(d->inHeader) { + // grab available lines + while(1) { + bool found; + QString line = extractLine(&d->recvBuf, &found); + if(!found) + break; + if(line.isEmpty()) { + d->inHeader = false; + break; + } + d->headerLines += line; + } + + // done with grabbing the header? + if(!d->inHeader) { + QString str = d->headerLines.first(); + d->headerLines.takeFirst(); + + QString proto; + int code; + QString msg; + if(!extractMainHeader(str, &proto, &code, &msg)) { +#ifdef PROX_DEBUG + fprintf(stderr, "HttpConnect: invalid header!\n"); +#endif + reset(true); + error(ErrProxyNeg); + return; + } + else { +#ifdef PROX_DEBUG + fprintf(stderr, "HttpConnect: header proto=%s code=%d msg=%s\n", qPrintable(proto), code, qPrintable(msg)); + for(QStringList::ConstIterator it = d->headerLines.begin(); it != d->headerLines.end(); ++it) + fprintf(stderr, "HttpConnect: * %s\n", qPrintable(*it)); +#endif + } + + if(code == 200) { // OK +#ifdef PROX_DEBUG + fprintf(stderr, "HttpConnect: << Success >>\n"); +#endif + d->active = true; + connected(); + + if(!d->recvBuf.isEmpty()) { + appendRead(d->recvBuf); + d->recvBuf.resize(0); + readyRead(); + return; + } + } + else { + int err; + QString errStr; + if(code == 407) { // Authentication failed + err = ErrProxyAuth; + errStr = tr("Authentication failed"); + } + else if(code == 404) { // Host not found + err = ErrHostNotFound; + errStr = tr("Host not found"); + } + else if(code == 403) { // Access denied + err = ErrProxyNeg; + errStr = tr("Access denied"); + } + else if(code == 503) { // Connection refused + err = ErrConnectionRefused; + errStr = tr("Connection refused"); + } + else { // invalid reply + err = ErrProxyNeg; + errStr = tr("Invalid reply"); + } + +#ifdef PROX_DEBUG + fprintf(stderr, "HttpConnect: << Error >> %s\n", qPrintable(errStr)); +#endif + reset(true); + error(err); + return; + } + } + } + } + else { + appendRead(block); + readyRead(); + return; + } +} + +void HttpConnect::sock_bytesWritten(int x) +{ + if(d->toWrite > 0) { + int size = x; + if(d->toWrite < x) + size = d->toWrite; + d->toWrite -= size; + x -= size; + } + + if(d->active && x > 0) + bytesWritten(x); +} + +void HttpConnect::sock_error(int x) +{ + if(d->active) { + reset(); + error(ErrRead); + } + else { + reset(true); + if(x == BSocket::ErrHostNotFound) + error(ErrProxyConnect); + else if(x == BSocket::ErrConnectionRefused) + error(ErrProxyConnect); + else if(x == BSocket::ErrRead) + error(ErrProxyNeg); + } +} + +// CS_NAMESPACE_END
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/httpconnect.h
Added
@@ -0,0 +1,67 @@ +/* + * httpconnect.h - HTTP "CONNECT" proxy + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef CS_HTTPCONNECT_H +#define CS_HTTPCONNECT_H + +#include "bytestream.h" + +// CS_NAMESPACE_BEGIN + +class HttpConnect : public ByteStream +{ + Q_OBJECT +public: + enum Error { ErrConnectionRefused = ErrCustom, ErrHostNotFound, ErrProxyConnect, ErrProxyNeg, ErrProxyAuth }; + HttpConnect(QObject *parent=0); + ~HttpConnect(); + + void setAuth(const QString &user, const QString &pass=""); + void connectToHost(const QString &proxyHost, int proxyPort, const QString &host, int port); + + // from ByteStream + bool isOpen() const; + void close(); + void write(const QByteArray &); + QByteArray read(int bytes=0); + int bytesAvailable() const; + int bytesToWrite() const; + +signals: + void connected(); + +private slots: + void sock_connected(); + void sock_connectionClosed(); + void sock_delayedCloseFinished(); + void sock_readyRead(); + void sock_bytesWritten(int); + void sock_error(int); + +private: + class Private; + Private *d; + + void reset(bool clear=false); +}; + +// CS_NAMESPACE_END + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/ice176.cpp
Added
@@ -0,0 +1,1342 @@ +/* + * Copyright (C) 2009,2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "ice176.h" + +#include <QSet> +#include <QTimer> +#include <QUdpSocket> +#include <QtCrypto> +#include "stuntransaction.h" +#include "stunbinding.h" +#include "stunmessage.h" +#include "udpportreserver.h" +#include "icelocaltransport.h" +#include "iceturntransport.h" +#include "icecomponent.h" + +namespace XMPP { + +enum +{ + Direct, + Relayed +}; + +static QChar randomPrintableChar() +{ + // 0-25 = a-z + // 26-51 = A-Z + // 52-61 = 0-9 + + uchar c = QCA::Random::randomChar() % 62; + if(c <= 25) + return 'a' + c; + else if(c <= 51) + return 'A' + (c - 26); + else + return '0' + (c - 52); +} + +static QString randomCredential(int len) +{ + QString out; + for(int n = 0; n < len; ++n) + out += randomPrintableChar(); + return out; +} + +static qint64 calc_pair_priority(int a, int b) +{ + qint64 priority = ((qint64)1 << 32) * qMin(a, b); + priority += (qint64)2 * qMax(a, b); + if(a > b) + ++priority; + return priority; +} + +// see if candidates are considered the same for pruning purposes +static bool compare_candidates(const IceComponent::CandidateInfo &a, const IceComponent::CandidateInfo &b) +{ + if(a.addr == b.addr && a.componentId == b.componentId) + return true; + else + return false; +} + +// scope values: 0 = local, 1 = link-local, 2 = private, 3 = public +// FIXME: dry (this is in psi avcall also) +static int getAddressScope(const QHostAddress &a) +{ + if(a.protocol() == QAbstractSocket::IPv6Protocol) + { + if(a == QHostAddress(QHostAddress::LocalHostIPv6)) + return 0; + else if(XMPP::Ice176::isIPv6LinkLocalAddress(a)) + return 1; + } + else if(a.protocol() == QAbstractSocket::IPv4Protocol) + { + quint32 v4 = a.toIPv4Address(); + quint8 a0 = v4 >> 24; + quint8 a1 = (v4 >> 16) & 0xff; + if(a0 == 127) + return 0; + else if(a0 == 169 && a1 == 254) + return 1; + else if(a0 == 10) + return 2; + else if(a0 == 172 && a1 >= 16 && a1 <= 31) + return 2; + else if(a0 == 192 && a1 == 168) + return 2; + } + + return 3; +} + +class Ice176::Private : public QObject +{ + Q_OBJECT + +public: + enum State + { + Stopped, + Starting, + Started, + Stopping + }; + + enum CandidatePairState + { + PWaiting, + PInProgress, + PSucceeded, + PFailed, + PFrozen + }; + + enum CheckListState + { + LRunning, + LCompleted, + LFailed + }; + + class CandidatePair + { + public: + IceComponent::CandidateInfo local, remote; + bool isDefault; + bool isValid; + bool isNominated; + CandidatePairState state; + + qint64 priority; + QString foundation; + + StunBinding *binding; + + // FIXME: this is wrong i think, it should be in LocalTransport + // or such, to multiplex ids + StunTransactionPool *pool; + + CandidatePair() : + binding(0), + pool(0) + { + } + }; + + class CheckList + { + public: + QList<CandidatePair> pairs; + CheckListState state; + }; + + class Component + { + public: + int id; + IceComponent *ic; + bool localFinished; + bool stopped; + bool lowOverhead; + + Component() : + localFinished(false), + stopped(false), + lowOverhead(false) + { + } + }; + + Ice176 *q; + Ice176::Mode mode; + State state; + TurnClient::Proxy proxy; + UdpPortReserver *portReserver; + int componentCount; + QList<Ice176::LocalAddress> localAddrs; + QList<Ice176::ExternalAddress> extAddrs; + QHostAddress stunBindAddr; + int stunBindPort; + QHostAddress stunRelayUdpAddr; + int stunRelayUdpPort; + QString stunRelayUdpUser; + QCA::SecureArray stunRelayUdpPass; + QHostAddress stunRelayTcpAddr; + int stunRelayTcpPort; + QString stunRelayTcpUser; + QCA::SecureArray stunRelayTcpPass; + QString localUser, localPass; + QString peerUser, peerPass; + QList<Component> components; + QList<IceComponent::Candidate> localCandidates; + QSet<IceTransport*> iceTransports; + CheckList checkList; + QList< QList<QByteArray> > in; + bool useLocal; + bool useStunBind; + bool useStunRelayUdp; + bool useStunRelayTcp; + bool useTrickle; + QTimer *collectTimer; + + Private(Ice176 *_q) : + QObject(_q), + q(_q), + state(Stopped), + portReserver(0), + componentCount(0), + useLocal(true), + useStunBind(true), + useStunRelayUdp(true), + useStunRelayTcp(true), + useTrickle(false), + collectTimer(0) + { + } + + ~Private() + { + if(collectTimer) + { + collectTimer->disconnect(this); + collectTimer->deleteLater(); + } + + foreach(const Component &c, components) + delete c.ic; + + for(int n = 0; n < checkList.pairs.count(); ++n) + { + StunBinding *binding = checkList.pairsn.binding; + StunTransactionPool *pool = checkList.pairsn.pool; + + delete binding; + + if(pool) + { + pool->disconnect(this); + pool->setParent(0); + pool->deleteLater(); + } + } + } + + void reset() + { + // TODO + } + + int findLocalAddress(const QHostAddress &addr) + { + for(int n = 0; n < localAddrs.count(); ++n) + { + if(localAddrsn.addr == addr) + return n; + } + + return -1; + } + + void updateLocalAddresses(const QList<LocalAddress> &addrs) + { + // for now, ignore address changes during operation + if(state != Stopped) + return; + + localAddrs.clear(); + foreach(const LocalAddress &la, addrs) + { + int at = findLocalAddress(la.addr); + if(at == -1) + localAddrs += la; + } + } + + void updateExternalAddresses(const QList<ExternalAddress> &addrs) + { + // for now, ignore address changes during operation + if(state != Stopped) + return; + + extAddrs.clear(); + foreach(const ExternalAddress &ea, addrs) + { + int at = findLocalAddress(ea.base.addr); + if(at != -1) + extAddrs += ea; + } + } + + void start() + { + Q_ASSERT(state == Stopped); + + state = Starting; + + localUser = randomCredential(4); + localPass = randomCredential(22); + + QList<QUdpSocket*> socketList; + if(portReserver) + socketList = portReserver->borrowSockets(componentCount, this); + + for(int n = 0; n < componentCount; ++n) + { + Component c; + c.id = n + 1; + c.ic = new IceComponent(c.id, this); + c.ic->setDebugLevel(IceComponent::DL_Info); + connect(c.ic, SIGNAL(candidateAdded(const XMPP::IceComponent::Candidate &)), SLOT(ic_candidateAdded(const XMPP::IceComponent::Candidate &))); + connect(c.ic, SIGNAL(candidateRemoved(const XMPP::IceComponent::Candidate &)), SLOT(ic_candidateRemoved(const XMPP::IceComponent::Candidate &))); + connect(c.ic, SIGNAL(localFinished()), SLOT(ic_localFinished())); + connect(c.ic, SIGNAL(stopped()), SLOT(ic_stopped())); + connect(c.ic, SIGNAL(debugLine(const QString &)), SLOT(ic_debugLine(const QString &))); + + c.ic->setClientSoftwareNameAndVersion("Iris"); + c.ic->setProxy(proxy); + if(portReserver) + c.ic->setPortReserver(portReserver); + c.ic->setLocalAddresses(localAddrs); + c.ic->setExternalAddresses(extAddrs); + if(!stunBindAddr.isNull()) + c.ic->setStunBindService(stunBindAddr, stunBindPort); + if(!stunRelayUdpAddr.isNull()) + c.ic->setStunRelayUdpService(stunRelayUdpAddr, stunRelayUdpPort, stunRelayUdpUser, stunRelayUdpPass); + if(!stunRelayTcpAddr.isNull()) + c.ic->setStunRelayTcpService(stunRelayTcpAddr, stunRelayTcpPort, stunRelayTcpUser, stunRelayTcpPass); + + c.ic->setUseLocal(useLocal); + c.ic->setUseStunBind(useStunBind); + c.ic->setUseStunRelayUdp(useStunRelayUdp); + c.ic->setUseStunRelayTcp(useStunRelayTcp); + + // create an inbound queue for this component + in += QList<QByteArray>(); + + components += c; + + c.ic->update(&socketList); + } + + // socketList should always empty here, but might not be if + // the app provided a different address list to + // UdpPortReserver and Ice176. and that would really be + // a dumb thing to do but I'm not going to Q_ASSERT it + if(!socketList.isEmpty()) + portReserver->returnSockets(socketList); + } + + void stop() + { + Q_ASSERT(state == Starting || state == Started); + + state = Stopping; + + if(!components.isEmpty()) + { + for(int n = 0; n < components.count(); ++n) + componentsn.ic->stop(); + } + else + { + // TODO: hmm, is it possible to have no components? + QMetaObject::invokeMethod(this, "postStop", Qt::QueuedConnection); + } + } + + void addRemoteCandidates(const QList<Candidate> &list) + { + QList<IceComponent::CandidateInfo> remoteCandidates; + foreach(const Candidate &c, list) + { + IceComponent::CandidateInfo ci; + ci.addr.addr = c.ip; + ci.addr.addr.setScopeId(QString()); + ci.addr.port = c.port; + ci.type = (IceComponent::CandidateType)string_to_candidateType(c.type); // TODO: handle error + ci.componentId = c.component; + ci.priority = c.priority; + ci.foundation = c.foundation; + if(!c.rel_addr.isNull()) + { + ci.base.addr = c.rel_addr; + ci.base.addr.setScopeId(QString()); + ci.base.port = c.rel_port; + } + ci.network = c.network; + ci.id = c.id; + remoteCandidates += ci; + } + + printf("adding %d remote candidates\n", remoteCandidates.count()); + + QList<CandidatePair> pairs; + foreach(const IceComponent::Candidate &cc, localCandidates) + { + const IceComponent::CandidateInfo &lc = cc.info; + + foreach(const IceComponent::CandidateInfo &rc, remoteCandidates) + { + if(lc.componentId != rc.componentId) + continue; + + // don't pair ipv4 with ipv6. FIXME: is this right? + if(lc.addr.addr.protocol() != rc.addr.addr.protocol()) + continue; + + // don't relay to localhost. turnserver + // doesn't like it. i don't know if this + // should qualify as a HACK or not. + // trying to relay to localhost is pretty + // stupid anyway + if(lc.type == IceComponent::RelayedType && getAddressScope(rc.addr.addr) == 0) + continue; + + CandidatePair pair; + pair.state = PFrozen; // FIXME: setting state here may be wrong + pair.local = lc; + pair.remote = rc; + if(pair.local.addr.addr.protocol() == QAbstractSocket::IPv6Protocol && isIPv6LinkLocalAddress(pair.local.addr.addr)) + pair.remote.addr.addr.setScopeId(pair.local.addr.addr.scopeId()); + pair.isDefault = false; + pair.isValid = false; + pair.isNominated = false; + if(mode == Ice176::Initiator) + pair.priority = calc_pair_priority(lc.priority, rc.priority); + else + pair.priority = calc_pair_priority(rc.priority, lc.priority); + pairs += pair; + } + } + + printf("%d pairs\n", pairs.count()); + + // combine pairs with existing, and sort + pairs = checkList.pairs + pairs; + checkList.pairs.clear(); + foreach(const CandidatePair &pair, pairs) + { + int at; + for(at = 0; at < checkList.pairs.count(); ++at) + { + if(compare_pair(pair, checkList.pairsat) < 0) + break; + } + + checkList.pairs.insert(at, pair); + } + + // pruning + + for(int n = 0; n < checkList.pairs.count(); ++n) + { + CandidatePair &pair = checkList.pairsn; + if(pair.local.type == IceComponent::ServerReflexiveType) + pair.local.addr = pair.local.base; + } + + for(int n = 0; n < checkList.pairs.count(); ++n) + { + CandidatePair &pair = checkList.pairsn; + printf("%d, %s:%d -> %s:%d\n", pair.local.componentId, qPrintable(pair.local.addr.addr.toString()), pair.local.addr.port, qPrintable(pair.remote.addr.addr.toString()), pair.remote.addr.port); + + bool found = false; + for(int i = n - 1; i >= 0; --i) + { + if(compare_candidates(pair.local, checkList.pairsi.local) && compare_candidates(pair.remote, checkList.pairsi.remote)) + { + found = true; + break; + } + } + + if(found ) + { + checkList.pairs.removeAt(n); + --n; // adjust position + } + } + + // max pairs is 100 * number of components + int max_pairs = 100 * components.count(); + while(checkList.pairs.count() > max_pairs) + checkList.pairs.removeLast(); + + printf("%d after pruning\n", checkList.pairs.count()); + + // set state + for(int n = 0; n < checkList.pairs.count(); ++n) + { + CandidatePair &pair = checkList.pairsn; + + // only initialize the new pairs + if(pair.state != PFrozen) + continue; + + pair.foundation = pair.local.foundation + pair.remote.foundation; + + // FIXME: for now we just do checks to everything immediately + pair.state = PInProgress; + + int at = findLocalCandidate(pair.local.addr.addr, pair.local.addr.port); + Q_ASSERT(at != -1); + + IceComponent::Candidate &lc = localCandidatesat; + + Component &c = componentsfindComponent(lc.info.componentId); + + pair.pool = new StunTransactionPool(StunTransaction::Udp, this); + connect(pair.pool, SIGNAL(outgoingMessage(const QByteArray &, const QHostAddress &, int)), SLOT(pool_outgoingMessage(const QByteArray &, const QHostAddress &, int))); + //pair.pool->setUsername(peerUser + ':' + localUser); + //pair.pool->setPassword(peerPass.toUtf8()); + + pair.binding = new StunBinding(pair.pool); + connect(pair.binding, SIGNAL(success()), SLOT(binding_success())); + + int prflx_priority = c.ic->peerReflexivePriority(lc.iceTransport, lc.path); + pair.binding->setPriority(prflx_priority); + + if(mode == Ice176::Initiator) + { + pair.binding->setIceControlling(0); + pair.binding->setUseCandidate(true); + } + else + pair.binding->setIceControlled(0); + + pair.binding->setShortTermUsername(peerUser + ':' + localUser); + pair.binding->setShortTermPassword(peerPass); + + pair.binding->start(); + } + } + + void write(int componentIndex, const QByteArray &datagram) + { + int at = -1; + for(int n = 0; n < checkList.pairs.count(); ++n) + { + if(checkList.pairsn.local.componentId - 1 == componentIndex && checkList.pairsn.isValid) + { + at = n; + break; + } + } + if(at == -1) + return; + + CandidatePair &pair = checkList.pairsat; + + at = findLocalCandidate(pair.local.addr.addr, pair.local.addr.port); + if(at == -1) // FIXME: assert? + return; + + IceComponent::Candidate &lc = localCandidatesat; + + IceTransport *sock = lc.iceTransport; + int path = lc.path; + + sock->writeDatagram(path, datagram, pair.remote.addr.addr, pair.remote.addr.port); + + // DOR-SR? + QMetaObject::invokeMethod(q, "datagramsWritten", Qt::QueuedConnection, Q_ARG(int, componentIndex), Q_ARG(int, 1)); + } + + void flagComponentAsLowOverhead(int componentIndex) + { + // FIXME: ok to assume in order? + Component &c = componentscomponentIndex; + c.lowOverhead = true; + + // FIXME: actually do something + } + +private: + int findComponent(const IceComponent *ic) const + { + for(int n = 0; n < components.count(); ++n) + { + if(componentsn.ic == ic) + return n; + } + + return -1; + } + + int findComponent(int id) const + { + for(int n = 0; n < components.count(); ++n) + { + if(componentsn.id == id) + return n; + } + + return -1; + } + + int findLocalCandidate(const IceTransport *iceTransport, int path) const + { + for(int n = 0; n < localCandidates.count(); ++n) + { + const IceComponent::Candidate &cc = localCandidatesn; + if(cc.iceTransport == iceTransport && cc.path == path) + return n; + } + + return -1; + } + + int findLocalCandidate(const QHostAddress &fromAddr, int fromPort) + { + for(int n = 0; n < localCandidates.count(); ++n) + { + const IceComponent::Candidate &cc = localCandidatesn; + if(cc.info.addr.addr == fromAddr && cc.info.addr.port == fromPort) + return n; + } + + return -1; + } + + static QString candidateType_to_string(IceComponent::CandidateType type) + { + QString out; + switch(type) + { + case IceComponent::HostType: out = "host"; break; + case IceComponent::PeerReflexiveType: out = "prflx"; break; + case IceComponent::ServerReflexiveType: out = "srflx"; break; + case IceComponent::RelayedType: out = "relay"; break; + default: Q_ASSERT(0); + } + return out; + } + + static int string_to_candidateType(const QString &in) + { + if(in == "host") + return IceComponent::HostType; + else if(in == "prflx") + return IceComponent::PeerReflexiveType; + else if(in == "srflx") + return IceComponent::ServerReflexiveType; + else if(in == "relay") + return IceComponent::RelayedType; + else + return -1; + } + + static int compare_pair(const CandidatePair &a, const CandidatePair &b) + { + // prefer remote srflx, for leap + if(a.remote.type == IceComponent::ServerReflexiveType && b.remote.type != IceComponent::ServerReflexiveType && b.remote.addr.addr.protocol() != QAbstractSocket::IPv6Protocol) + return -1; + else if(b.remote.type == IceComponent::ServerReflexiveType && a.remote.type != IceComponent::ServerReflexiveType && a.remote.addr.addr.protocol() != QAbstractSocket::IPv6Protocol) + return 1; + + if(a.priority > b.priority) + return -1; + else if(b.priority > a.priority) + return 1; + + return 0; + } + +private slots: + void postStop() + { + state = Stopped; + emit q->stopped(); + } + + void ic_candidateAdded(const XMPP::IceComponent::Candidate &_cc) + { + IceComponent::Candidate cc = _cc; + cc.info.id = randomCredential(10); // FIXME: ensure unique + cc.info.foundation = "0"; // FIXME + // TODO + localCandidates += cc; + + printf("C%d: candidate added: %s;%d\n", cc.info.componentId, qPrintable(cc.info.addr.addr.toString()), cc.info.addr.port); + + if(!iceTransports.contains(cc.iceTransport)) + { + connect(cc.iceTransport, SIGNAL(readyRead(int)), SLOT(it_readyRead(int))); + connect(cc.iceTransport, SIGNAL(datagramsWritten(int, int, const QHostAddress &, int)), SLOT(it_datagramsWritten(int, int, const QHostAddress &, int))); + + iceTransports += cc.iceTransport; + } + + if(state == Started && useTrickle) + { + QList<Ice176::Candidate> list; + + Ice176::Candidate c; + c.component = cc.info.componentId; + c.foundation = cc.info.foundation; + c.generation = 0; // TODO + c.id = cc.info.id; + c.ip = cc.info.addr.addr; + c.ip.setScopeId(QString()); + c.network = cc.info.network; + c.port = cc.info.addr.port; + c.priority = cc.info.priority; + c.protocol = "udp"; + if(cc.info.type != IceComponent::HostType) + { + c.rel_addr = cc.info.base.addr; + c.rel_addr.setScopeId(QString()); + c.rel_port = cc.info.base.port; + } + else + { + c.rel_addr = QHostAddress(); + c.rel_port = -1; + } + c.rem_addr = QHostAddress(); + c.rem_port = -1; + c.type = candidateType_to_string(cc.info.type); + list += c; + + emit q->localCandidatesReady(list); + } + } + + void ic_candidateRemoved(const XMPP::IceComponent::Candidate &cc) + { + // TODO + printf("C%d: candidate removed: %s;%d\n", cc.info.componentId, qPrintable(cc.info.addr.addr.toString()), cc.info.addr.port); + + QStringList idList; + for(int n = 0; n < localCandidates.count(); ++n) + { + if(localCandidatesn.id == cc.id && localCandidatesn.info.componentId == cc.info.componentId) + { + // FIXME: this is rather ridiculous I think + idList += localCandidatesn.info.id; + + localCandidates.removeAt(n); + --n; // adjust position + } + } + + bool iceTransportInUse = false; + foreach(const IceComponent::Candidate &lc, localCandidates) + { + if(lc.iceTransport == cc.iceTransport) + { + iceTransportInUse = true; + break; + } + } + if(!iceTransportInUse) + { + cc.iceTransport->disconnect(this); + iceTransports.remove(cc.iceTransport); + } + + for(int n = 0; n < checkList.pairs.count(); ++n) + { + if(idList.contains(checkList.pairsn.local.id)) + { + StunBinding *binding = checkList.pairsn.binding; + StunTransactionPool *pool = checkList.pairsn.pool; + + delete binding; + + if(pool) + { + pool->disconnect(this); + pool->setParent(0); + pool->deleteLater(); + } + + checkList.pairs.removeAt(n); + --n; // adjust position + } + } + } + + void ic_localFinished() + { + IceComponent *ic = (IceComponent *)sender(); + int at = findComponent(ic); + Q_ASSERT(at != -1); + + componentsat.localFinished = true; + + bool allFinished = true; + foreach(const Component &c, components) + { + if(!c.localFinished) + { + allFinished = false; + break; + } + } + + if(allFinished) + { + state = Started; + + emit q->started(); + + if(!useTrickle) + { + // FIXME: there should be a way to not wait if + // we know for sure there is nothing else + // possibly coming + collectTimer = new QTimer(this); + connect(collectTimer, SIGNAL(timeout()), SLOT(collect_timeout())); + collectTimer->setSingleShot(true); + collectTimer->start(4000); + return; + } + + // FIXME: DOR-SS + QList<Ice176::Candidate> list; + foreach(const IceComponent::Candidate &cc, localCandidates) + { + Ice176::Candidate c; + c.component = cc.info.componentId; + c.foundation = cc.info.foundation; + c.generation = 0; // TODO + c.id = cc.info.id; + c.ip = cc.info.addr.addr; + c.ip.setScopeId(QString()); + c.network = cc.info.network; + c.port = cc.info.addr.port; + c.priority = cc.info.priority; + c.protocol = "udp"; + if(cc.info.type != IceComponent::HostType) + { + c.rel_addr = cc.info.base.addr; + c.rel_addr.setScopeId(QString()); + c.rel_port = cc.info.base.port; + } + else + { + c.rel_addr = QHostAddress(); + c.rel_port = -1; + } + c.rem_addr = QHostAddress(); + c.rem_port = -1; + c.type = candidateType_to_string(cc.info.type); + list += c; + } + if(!list.isEmpty()) + emit q->localCandidatesReady(list); + } + } + + void ic_stopped() + { + IceComponent *ic = (IceComponent *)sender(); + int at = findComponent(ic); + Q_ASSERT(at != -1); + + componentsat.stopped = true; + + bool allStopped = true; + foreach(const Component &c, components) + { + if(!c.stopped) + { + allStopped = false; + break; + } + } + + if(allStopped) + postStop(); + } + + void ic_debugLine(const QString &line) + { + IceComponent *ic = (IceComponent *)sender(); + int at = findComponent(ic); + Q_ASSERT(at != -1); + + // FIXME: components are always sorted? + printf("C%d: %s\n", at + 1, qPrintable(line)); + } + + void collect_timeout() + { + collectTimer->disconnect(this); + collectTimer->deleteLater(); + collectTimer = 0; + + QList<Ice176::Candidate> list; + foreach(const IceComponent::Candidate &cc, localCandidates) + { + Ice176::Candidate c; + c.component = cc.info.componentId; + c.foundation = cc.info.foundation; + c.generation = 0; // TODO + c.id = cc.info.id; + c.ip = cc.info.addr.addr; + c.ip.setScopeId(QString()); + c.network = cc.info.network; + c.port = cc.info.addr.port; + c.priority = cc.info.priority; + c.protocol = "udp"; + if(cc.info.type != IceComponent::HostType) + { + c.rel_addr = cc.info.base.addr; + c.rel_addr.setScopeId(QString()); + c.rel_port = cc.info.base.port; + } + else + { + c.rel_addr = QHostAddress(); + c.rel_port = -1; + } + c.rem_addr = QHostAddress(); + c.rem_port = -1; + c.type = candidateType_to_string(cc.info.type); + list += c; + } + if(!list.isEmpty()) + emit q->localCandidatesReady(list); + } + + void it_readyRead(int path) + { + IceTransport *it = (IceTransport *)sender(); + int at = findLocalCandidate(it, path); + Q_ASSERT(at != -1); + + IceComponent::Candidate &cc = localCandidatesat; + + IceTransport *sock = it; + + while(sock->hasPendingDatagrams(path)) + { + QHostAddress fromAddr; + int fromPort; + QByteArray buf = sock->readDatagram(path, &fromAddr, &fromPort); + + //printf("port %d: received packet (%d bytes)\n", lt->sock->localPort(), buf.size()); + + QString requser = localUser + ':' + peerUser; + QByteArray reqkey = localPass.toUtf8(); + + StunMessage::ConvertResult result; + StunMessage msg = StunMessage::fromBinary(buf, &result, StunMessage::MessageIntegrity | StunMessage::Fingerprint, reqkey); + if(!msg.isNull() && (msg.mclass() == StunMessage::Request || msg.mclass() == StunMessage::Indication)) + { + printf("received validated request or indication from %s:%d\n", qPrintable(fromAddr.toString()), fromPort); + QString user = QString::fromUtf8(msg.attribute(0x0006)); // USERNAME + if(requser != user) + { + printf("user %s is wrong. it should be %s. skipping\n", qPrintable(user), qPrintable(requser)); + continue; + } + + if(msg.method() != 0x001) + { + printf("not a binding request. skipping\n"); + continue; + } + + StunMessage response; + response.setClass(StunMessage::SuccessResponse); + response.setMethod(0x001); + response.setId(msg.id()); + + quint16 port16 = fromPort; + quint32 addr4 = fromAddr.toIPv4Address(); + QByteArray val(8, 0); + quint8 *p = (quint8 *)val.data(); + const quint8 *magic = response.magic(); + p0 = 0; + p1 = 0x01; + p2 = (port16 >> 8) & 0xff; + p2 ^= magic0; + p3 = port16 & 0xff; + p3 ^= magic1; + p4 = (addr4 >> 24) & 0xff; + p4 ^= magic0; + p5 = (addr4 >> 16) & 0xff; + p5 ^= magic1; + p6 = (addr4 >> 8) & 0xff; + p6 ^= magic2; + p7 = addr4 & 0xff; + p7 ^= magic3; + + QList<StunMessage::Attribute> list; + StunMessage::Attribute attr; + attr.type = 0x0020; + attr.value = val; + list += attr; + + response.setAttributes(list); + + QByteArray packet = response.toBinary(StunMessage::MessageIntegrity | StunMessage::Fingerprint, reqkey); + sock->writeDatagram(path, packet, fromAddr, fromPort); + } + else + { + QByteArray reskey = peerPass.toUtf8(); + StunMessage msg = StunMessage::fromBinary(buf, &result, StunMessage::MessageIntegrity | StunMessage::Fingerprint, reskey); + if(!msg.isNull() && (msg.mclass() == StunMessage::SuccessResponse || msg.mclass() == StunMessage::ErrorResponse)) + { + printf("received validated response\n"); + + // FIXME: this is so gross and completely defeats the point of having pools + for(int n = 0; n < checkList.pairs.count(); ++n) + { + CandidatePair &pair = checkList.pairsn; + if(pair.local.addr.addr == cc.info.addr.addr && pair.local.addr.port == cc.info.addr.port) + pair.pool->writeIncomingMessage(msg); + } + } + else + { + //printf("received some non-stun or invalid stun packet\n"); + + // FIXME: i don't know if this is good enough + if(StunMessage::isProbablyStun(buf)) + { + printf("unexpected stun packet (loopback?), skipping.\n"); + continue; + } + + int at = -1; + for(int n = 0; n < checkList.pairs.count(); ++n) + { + CandidatePair &pair = checkList.pairsn; + if(pair.local.addr.addr == cc.info.addr.addr && pair.local.addr.port == cc.info.addr.port) + { + at = n; + break; + } + } + if(at == -1) + { + printf("the local transport does not seem to be associated with a candidate?!\n"); + continue; + } + + int componentIndex = checkList.pairsat.local.componentId - 1; + //printf("packet is considered to be application data for component index %d\n", componentIndex); + + // FIXME: this assumes components are ordered by id in our local arrays + incomponentIndex += buf; + emit q->readyRead(componentIndex); + } + } + } + } + + void it_datagramsWritten(int path, int count, const QHostAddress &addr, int port) + { + // TODO + Q_UNUSED(path); + Q_UNUSED(count); + Q_UNUSED(addr); + Q_UNUSED(port); + } + + void pool_outgoingMessage(const QByteArray &packet, const QHostAddress &addr, int port) + { + Q_UNUSED(addr); + Q_UNUSED(port); + + StunTransactionPool *pool = (StunTransactionPool *)sender(); + int at = -1; + for(int n = 0; n < checkList.pairs.count(); ++n) + { + if(checkList.pairsn.pool == pool) + { + at = n; + break; + } + } + if(at == -1) // FIXME: assert? + return; + + CandidatePair &pair = checkList.pairsat; + + at = findLocalCandidate(pair.local.addr.addr, pair.local.addr.port); + if(at == -1) // FIXME: assert? + return; + + IceComponent::Candidate &lc = localCandidatesat; + + IceTransport *sock = lc.iceTransport; + int path = lc.path; + + printf("connectivity check from %s:%d to %s:%d\n", qPrintable(pair.local.addr.addr.toString()), pair.local.addr.port, qPrintable(pair.remote.addr.addr.toString()), pair.remote.addr.port); + sock->writeDatagram(path, packet, pair.remote.addr.addr, pair.remote.addr.port); + } + + void binding_success() + { + StunBinding *binding = (StunBinding *)sender(); + int at = -1; + for(int n = 0; n < checkList.pairs.count(); ++n) + { + if(checkList.pairsn.binding == binding) + { + at = n; + break; + } + } + if(at == -1) + return; + + printf("check success\n"); + + CandidatePair &pair = checkList.pairsat; + + // TODO: if we were cool, we'd do something with the peer + // reflexive address received + + // TODO: we're also supposed to do triggered checks. except + // that currently we check everything anyway so this is not + // relevant + + // check if there's a candidate already valid + at = -1; + for(int n = 0; n < checkList.pairs.count(); ++n) + { + if(checkList.pairsn.local.componentId == pair.local.componentId && checkList.pairsn.isValid) + { + at = n; + break; + } + } + + pair.isValid = true; + + if(at == -1) + { + int at = findComponent(pair.local.componentId); + Component &c = componentsat; + if(c.lowOverhead) + { + printf("component is flagged for low overhead. setting up for %s;%d -> %s;%d\n", + qPrintable(pair.local.addr.addr.toString()), pair.local.addr.port, qPrintable(pair.remote.addr.addr.toString()), pair.remote.addr.port); + at = findLocalCandidate(pair.local.addr.addr, pair.local.addr.port); + IceComponent::Candidate &cc = localCandidatesat; + c.ic->flagPathAsLowOverhead(cc.id, pair.remote.addr.addr, pair.remote.addr.port); + } + + emit q->componentReady(pair.local.componentId - 1); + } + else + { + printf("component %d already active, not signalling\n", pair.local.componentId); + } + } +}; + +Ice176::Ice176(QObject *parent) : + QObject(parent) +{ + d = new Private(this); +} + +Ice176::~Ice176() +{ + delete d; +} + +void Ice176::reset() +{ + d->reset(); +} + +void Ice176::setProxy(const TurnClient::Proxy &proxy) +{ + d->proxy = proxy; +} + +void Ice176::setPortReserver(UdpPortReserver *portReserver) +{ + Q_ASSERT(d->state == Private::Stopped); + + d->portReserver = portReserver; +} + +void Ice176::setLocalAddresses(const QList<LocalAddress> &addrs) +{ + d->updateLocalAddresses(addrs); +} + +void Ice176::setExternalAddresses(const QList<ExternalAddress> &addrs) +{ + d->updateExternalAddresses(addrs); +} + +void Ice176::setStunBindService(const QHostAddress &addr, int port) +{ + d->stunBindAddr = addr; + d->stunBindPort = port; +} + +void Ice176::setStunRelayUdpService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass) +{ + d->stunRelayUdpAddr = addr; + d->stunRelayUdpPort = port; + d->stunRelayUdpUser = user; + d->stunRelayUdpPass = pass; +} + +void Ice176::setStunRelayTcpService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass) +{ + d->stunRelayTcpAddr = addr; + d->stunRelayTcpPort = port; + d->stunRelayTcpUser = user; + d->stunRelayTcpPass = pass; +} + +void Ice176::setUseLocal(bool enabled) +{ + d->useLocal = enabled; +} + +void Ice176::setUseStunBind(bool enabled) +{ + d->useStunBind = enabled; +} + +void Ice176::setUseStunRelayUdp(bool enabled) +{ + d->useStunRelayUdp = enabled; +} + +void Ice176::setUseStunRelayTcp(bool enabled) +{ + d->useStunRelayTcp = enabled; +} + +void Ice176::setComponentCount(int count) +{ + Q_ASSERT(d->state == Private::Stopped); + + d->componentCount = count; +} + +void Ice176::setLocalCandidateTrickle(bool enabled) +{ + d->useTrickle = enabled; +} + +void Ice176::start(Mode mode) +{ + d->mode = mode; + d->start(); +} + +void Ice176::stop() +{ + d->stop(); +} + +QString Ice176::localUfrag() const +{ + return d->localUser; +} + +QString Ice176::localPassword() const +{ + return d->localPass; +} + +void Ice176::setPeerUfrag(const QString &ufrag) +{ + d->peerUser = ufrag; +} + +void Ice176::setPeerPassword(const QString &pass) +{ + d->peerPass = pass; +} + +void Ice176::addRemoteCandidates(const QList<Candidate> &list) +{ + d->addRemoteCandidates(list); +} + +bool Ice176::hasPendingDatagrams(int componentIndex) const +{ + return !d->incomponentIndex.isEmpty(); +} + +QByteArray Ice176::readDatagram(int componentIndex) +{ + return d->incomponentIndex.takeFirst(); +} + +void Ice176::writeDatagram(int componentIndex, const QByteArray &datagram) +{ + d->write(componentIndex, datagram); +} + +void Ice176::flagComponentAsLowOverhead(int componentIndex) +{ + d->flagComponentAsLowOverhead(componentIndex); +} + +bool Ice176::isIPv6LinkLocalAddress(const QHostAddress &addr) +{ + Q_ASSERT(addr.protocol() == QAbstractSocket::IPv6Protocol); + Q_IPV6ADDR addr6 = addr.toIPv6Address(); + quint16 hi = addr60; + hi <<= 8; + hi += addr61; + if((hi & 0xffc0) == 0xfe80) + return true; + else + return false; +} + +} + +#include "ice176.moc"
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/ice176.h
Added
@@ -0,0 +1,189 @@ +/* + * Copyright (C) 2009,2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef ICE176_H +#define ICE176_H + +#include <QObject> +#include <QString> +#include <QHostAddress> +#include "turnclient.h" + +namespace QCA { + class SecureArray; +} + +namespace XMPP { + +class UdpPortReserver; + +class Ice176 : public QObject +{ + Q_OBJECT + +public: + enum Error + { + ErrorGeneric + }; + + enum Mode + { + Initiator, + Responder + }; + + class LocalAddress + { + public: + QHostAddress addr; + int network; // -1 = unknown + bool isVpn; + + LocalAddress() : + network(-1), + isVpn(false) + { + } + }; + + class ExternalAddress + { + public: + LocalAddress base; + QHostAddress addr; + int portBase; // -1 = same as base + + ExternalAddress() : + portBase(-1) + { + } + }; + + class Candidate + { + public: + int component; + QString foundation; + int generation; + QString id; + QHostAddress ip; + int network; // -1 = unknown + int port; + int priority; + QString protocol; + QHostAddress rel_addr; + int rel_port; + QHostAddress rem_addr; + int rem_port; + QString type; + + Candidate() : + component(-1), + generation(-1), + network(-1), + port(-1), + priority(-1), + rel_port(-1), + rem_port(-1) + { + } + }; + + Ice176(QObject *parent = 0); + ~Ice176(); + + void reset(); + + void setProxy(const TurnClient::Proxy &proxy); + + // if set, ports will be drawn from the reserver if possible, before + // binding to random ports + // note: ownership is not passed + void setPortReserver(UdpPortReserver *portReserver); + + void setLocalAddresses(const QList<LocalAddress> &addrs); + + // one per local address. you must set local addresses first. + void setExternalAddresses(const QList<ExternalAddress> &addrs); + + void setStunBindService(const QHostAddress &addr, int port); + void setStunRelayUdpService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass); + void setStunRelayTcpService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass); + + // these all start out enabled, but can be disabled for diagnostic + // purposes + void setUseLocal(bool enabled); + void setUseStunBind(bool enabled); + void setUseStunRelayUdp(bool enabled); + void setUseStunRelayTcp(bool enabled); + + void setComponentCount(int count); + void setLocalCandidateTrickle(bool enabled); // default false + + void start(Mode mode); + void stop(); + + QString localUfrag() const; + QString localPassword() const; + + void setPeerUfrag(const QString &ufrag); + void setPeerPassword(const QString &pass); + + void addRemoteCandidates(const QList<Candidate> &list); + + bool hasPendingDatagrams(int componentIndex) const; + QByteArray readDatagram(int componentIndex); + void writeDatagram(int componentIndex, const QByteArray &datagram); + + // this call will ensure that TURN headers are minimized on this + // component, with the drawback that packets might not be able to + // be set as non-fragmentable. use this on components that expect + // to send lots of very small packets, where header overhead is the + // most costly but also where fragmentation is impossible anyway. + // in short, use this on audio, but not on video. + void flagComponentAsLowOverhead(int componentIndex); + + // FIXME: this should probably be in netinterface.h or such + static bool isIPv6LinkLocalAddress(const QHostAddress &addr); + +signals: + // indicates that the ice engine is started and is ready to receive + // peer creds and remote candidates + void started(); + + void stopped(); + void error(XMPP::Ice176::Error e); + + void localCandidatesReady(const QList<XMPP::Ice176::Candidate> &list); + void componentReady(int index); + + void readyRead(int componentIndex); + void datagramsWritten(int componentIndex, int count); + +private: + class Private; + friend class Private; + Private *d; +}; + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/icecomponent.cpp
Added
@@ -0,0 +1,1056 @@ +/* + * Copyright (C) 2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "icecomponent.h" + +#include <QUdpSocket> +#include <QtCrypto> +#include "objectsession.h" +#include "udpportreserver.h" +#include "icelocaltransport.h" +#include "iceturntransport.h" + +namespace XMPP { + +static int calc_priority(int typePref, int localPref, int componentId) +{ + Q_ASSERT(typePref >= 0 && typePref <= 126); + Q_ASSERT(localPref >= 0 && localPref <= 65535); + Q_ASSERT(componentId >= 1 && componentId <= 256); + + int priority = (1 << 24) * typePref; + priority += (1 << 8) * localPref; + priority += (256 - componentId); + return priority; +} + +class IceComponent::Private : public QObject +{ + Q_OBJECT + +public: + class Config + { + public: + QList<Ice176::LocalAddress> localAddrs; + QList<Ice176::ExternalAddress> extAddrs; + + QHostAddress stunBindAddr; + int stunBindPort; + + QHostAddress stunRelayUdpAddr; + int stunRelayUdpPort; + QString stunRelayUdpUser; + QCA::SecureArray stunRelayUdpPass; + + QHostAddress stunRelayTcpAddr; + int stunRelayTcpPort; + QString stunRelayTcpUser; + QCA::SecureArray stunRelayTcpPass; + }; + + class LocalTransport + { + public: + QUdpSocket *qsock; + bool borrowedSocket; + QHostAddress addr; + IceLocalTransport *sock; + int network; + bool isVpn; + bool started; + bool stun_started; + bool stun_finished, turn_finished; + QHostAddress extAddr; + bool ext_finished; + + LocalTransport() : + qsock(0), + borrowedSocket(false), + sock(0), + network(-1), + isVpn(false), + started(false), + stun_started(false), + stun_finished(false), + turn_finished(false), + ext_finished(false) + { + } + }; + + IceComponent *q; + ObjectSession sess; + int id; + QString clientSoftware; + TurnClient::Proxy proxy; + UdpPortReserver *portReserver; + Config pending; + Config config; + bool stopping; + QList<LocalTransport*> localLeap; + QList<LocalTransport*> localStun; + IceTurnTransport *tt; + QList<Candidate> localCandidates; + QHash<int, QSet<TransportAddress> > channelPeers; + bool useLocal; + bool useStunBind; + bool useStunRelayUdp; + bool useStunRelayTcp; + bool local_finished; + int debugLevel; + + Private(IceComponent *_q) : + QObject(_q), + q(_q), + sess(this), + portReserver(0), + stopping(false), + tt(0), + useLocal(true), + useStunBind(true), + useStunRelayUdp(true), + useStunRelayTcp(true), + local_finished(false), + debugLevel(DL_None) + { + } + + ~Private() + { + QList<QUdpSocket*> socketsToReturn; + + for(int n = 0; n < localLeap.count(); ++n) + { + delete localLeapn->sock; + + if(localLeapn->borrowedSocket) + socketsToReturn += localLeapn->qsock; + else + localLeapn->qsock->deleteLater(); + } + + if(!socketsToReturn.isEmpty()) + portReserver->returnSockets(socketsToReturn); + + qDeleteAll(localLeap); + + for(int n = 0; n < localStun.count(); ++n) + delete localStunn->sock; + + qDeleteAll(localStun); + + delete tt; + } + + void update(QList<QUdpSocket*> *socketList) + { + Q_ASSERT(!stopping); + + // for now, only allow setting localAddrs once + if(!pending.localAddrs.isEmpty() && config.localAddrs.isEmpty()) + { + foreach(const Ice176::LocalAddress &la, pending.localAddrs) + { + // skip duplicate addrs + if(findLocalAddr(la.addr) != -1) + continue; + + if(!useLocal) + { + // skip out, but log the address in + // case we need it for stun + config.localAddrs += la; + continue; + } + + QUdpSocket *qsock = 0; + if(socketList) + qsock = takeFromSocketList(socketList, la.addr, this); + + bool borrowedSocket; + if(qsock) + { + borrowedSocket = true; + } + else + { + // otherwise, bind to random + qsock = new QUdpSocket(this); + if(!qsock->bind(la.addr, 0)) + { + delete qsock; + emit q->debugLine("Warning: unable to bind to random port."); + continue; + } + + borrowedSocket = false; + } + + int port = qsock->localPort(); + + config.localAddrs += la; + + LocalTransport *lt = new LocalTransport; + lt->addr = la.addr; + lt->qsock = qsock; + lt->borrowedSocket = borrowedSocket; + lt->sock = new IceLocalTransport(this); + lt->sock->setDebugLevel((IceTransport::DebugLevel)debugLevel); + lt->network = la.network; + lt->isVpn = la.isVpn; + connect(lt->sock, SIGNAL(started()), SLOT(lt_started())); + connect(lt->sock, SIGNAL(stopped()), SLOT(lt_stopped())); + connect(lt->sock, SIGNAL(addressesChanged()), SLOT(lt_addressesChanged())); + connect(lt->sock, SIGNAL(error(int)), SLOT(lt_error(int))); + connect(lt->sock, SIGNAL(debugLine(const QString &)), SLOT(lt_debugLine(const QString &))); + localLeap += lt; + + lt->sock->start(qsock); + emit q->debugLine(QString("starting transport ") + la.addr.toString() + ';' + QString::number(port) + " for component " + QString::number(id)); + } + } + + // extAddrs created on demand if present, but only once + if(!pending.extAddrs.isEmpty() && config.extAddrs.isEmpty()) + { + config.extAddrs = pending.extAddrs; + + bool need_doExt = false; + + foreach(LocalTransport *lt, localLeap) + { + // already assigned an ext address? skip + if(!lt->extAddr.isNull()) + continue; + + QHostAddress laddr = lt->sock->localAddress(); + int lport = lt->sock->localPort(); + + int at = -1; + for(int n = 0; n < config.extAddrs.count(); ++n) + { + const Ice176::ExternalAddress &ea = config.extAddrsn; + if(laddr.protocol() != QAbstractSocket::IPv6Protocol && ea.base.addr == laddr && (ea.portBase == -1 || ea.portBase == lport)) + { + at = n; + break; + } + } + + if(at != -1) + { + lt->extAddr = config.extAddrsat.addr; + if(lt->started) + need_doExt = true; + } + } + + if(need_doExt) + sess.defer(this, "doExt"); + } + + // only allow setting stun stuff once + if(!pending.stunBindAddr.isNull() && config.stunBindAddr.isNull()) + { + config.stunBindAddr = pending.stunBindAddr; + config.stunBindPort = pending.stunBindPort; + config.stunRelayUdpAddr = pending.stunRelayUdpAddr; + config.stunRelayUdpPort = pending.stunRelayUdpPort; + config.stunRelayUdpUser = pending.stunRelayUdpUser; + config.stunRelayUdpPass = pending.stunRelayUdpPass; + config.stunRelayTcpAddr = pending.stunRelayTcpAddr; + config.stunRelayTcpPort = pending.stunRelayTcpPort; + config.stunRelayTcpUser = pending.stunRelayTcpUser; + config.stunRelayTcpPass = pending.stunRelayTcpPass; + } + + // localStun sockets created on demand if stun settings are + // present, but only once (cannot be changed, for now) + if(((useStunBind && !config.stunBindAddr.isNull()) || (useStunRelayUdp && !config.stunRelayUdpAddr.isNull() && !config.stunRelayUdpUser.isEmpty())) && !config.localAddrs.isEmpty() && localStun.isEmpty()) + { + foreach(const Ice176::LocalAddress &la, config.localAddrs) + { + // don't setup stun ports for ipv6 + if(la.addr.protocol() == QAbstractSocket::IPv6Protocol) + continue; + + LocalTransport *lt = new LocalTransport; + lt->addr = la.addr; + lt->sock = new IceLocalTransport(this); + lt->sock->setDebugLevel((IceTransport::DebugLevel)debugLevel); + lt->network = la.network; + lt->isVpn = la.isVpn; + connect(lt->sock, SIGNAL(started()), SLOT(lt_started())); + connect(lt->sock, SIGNAL(stopped()), SLOT(lt_stopped())); + connect(lt->sock, SIGNAL(addressesChanged()), SLOT(lt_addressesChanged())); + connect(lt->sock, SIGNAL(error(int)), SLOT(lt_error(int))); + connect(lt->sock, SIGNAL(debugLine(const QString &)), SLOT(lt_debugLine(const QString &))); + localStun += lt; + + lt->sock->setClientSoftwareNameAndVersion(clientSoftware); + lt->sock->start(la.addr); + emit q->debugLine(QString("starting transport ") + la.addr.toString() + ";(dyn)" + " for component " + QString::number(id)); + } + } + + if((!config.stunBindAddr.isNull() || !config.stunRelayUdpAddr.isNull()) && !localStun.isEmpty()) + { + for(int n = 0; n < localStun.count(); ++n) + { + if(localStunn->started && !localStunn->stun_started) + tryStun(n); + } + } + + if(useStunRelayTcp && !config.stunRelayTcpAddr.isNull() && !config.stunRelayTcpUser.isEmpty() && !tt) + { + tt = new IceTurnTransport(this); + tt->setDebugLevel((IceTransport::DebugLevel)debugLevel); + connect(tt, SIGNAL(started()), SLOT(tt_started())); + connect(tt, SIGNAL(stopped()), SLOT(tt_stopped())); + connect(tt, SIGNAL(error(int)), SLOT(tt_error(int))); + connect(tt, SIGNAL(debugLine(const QString &)), SLOT(tt_debugLine(const QString &))); + tt->setClientSoftwareNameAndVersion(clientSoftware); + tt->setProxy(proxy); + tt->setUsername(config.stunRelayTcpUser); + tt->setPassword(config.stunRelayTcpPass); + tt->start(config.stunRelayTcpAddr, config.stunRelayTcpPort); + + emit q->debugLine(QString("starting TURN transport with server ") + config.stunRelayTcpAddr.toString() + ';' + QString::number(config.stunRelayTcpPort) + " for component " + QString::number(id)); + } + + if(localLeap.isEmpty() && localStun.isEmpty() && !local_finished) + { + local_finished = true; + sess.defer(q, "localFinished"); + } + } + + void stop() + { + Q_ASSERT(!stopping); + + stopping = true; + + // nothing to stop? + if(allStopped()) + { + sess.defer(this, "postStop"); + return; + } + + foreach(LocalTransport *lt, localLeap) + lt->sock->stop(); + + foreach(LocalTransport *lt, localStun) + lt->sock->stop(); + + if(tt) + tt->stop(); + } + + int peerReflexivePriority(const IceTransport *iceTransport, int path) const + { + int addrAt = -1; + const IceLocalTransport *lt = qobject_cast<const IceLocalTransport*>(iceTransport); + if(lt) + { + bool isLocalLeap = false; + addrAt = findLocalTransport(lt, &isLocalLeap); + if(addrAt != -1 && path == 1) + { + // lower priority, but not as far as IceTurnTransport + addrAt += 512; + } + } + else if(qobject_cast<const IceTurnTransport*>(iceTransport) == tt) + { + // lower priority by making it seem like the last nic + addrAt = 1024; + } + + Q_ASSERT(addrAt != -1); + + return choose_default_priority(PeerReflexiveType, 65535 - addrAt, false, id); + } + + void flagPathAsLowOverhead(int id, const QHostAddress &addr, int port) + { + int at = -1; + for(int n = 0; n < localCandidates.count(); ++n) + { + if(localCandidatesn.id == id) + { + at = n; + break; + } + } + + Q_ASSERT(at != -1); + + Candidate &c = localCandidatesat; + + TransportAddress ta(addr, port); + QSet<TransportAddress> &addrs = channelPeersc.id; + if(!addrs.contains(ta)) + { + addrs += ta; + c.iceTransport->addChannelPeer(ta.addr, ta.port); + } + } + +private: + // localPref is the priority of the network interface being used for + // this candidate. the value must be between 0-65535 and different + // interfaces must have different values. if there is only one + // interface, the value should be 65535. + static int choose_default_priority(CandidateType type, int localPref, bool isVpn, int componentId) + { + int typePref; + if(type == HostType) + { + if(isVpn) + typePref = 0; + else + typePref = 126; + } + else if(type == PeerReflexiveType) + typePref = 110; + else if(type == ServerReflexiveType) + typePref = 100; + else // RelayedType + typePref = 0; + + return calc_priority(typePref, localPref, componentId); + } + + static QUdpSocket *takeFromSocketList(QList<QUdpSocket*> *socketList, const QHostAddress &addr, QObject *parent = 0) + { + for(int n = 0; n < socketList->count(); ++n) + { + if((*socketList)n->localAddress() == addr) + { + QUdpSocket *sock = socketList->takeAt(n); + sock->setParent(parent); + return sock; + } + } + + return 0; + } + + int getId() const + { + for(int n = 0;; ++n) + { + bool found = false; + foreach(const Candidate &c, localCandidates) + { + if(c.id == n) + { + found = true; + break; + } + } + + if(!found) + return n; + } + } + + int findLocalAddr(const QHostAddress &addr) + { + for(int n = 0; n < config.localAddrs.count(); ++n) + { + if(config.localAddrsn.addr == addr) + return n; + } + + return -1; + } + + int findLocalTransport(const IceLocalTransport *sock, bool *isLocalLeap) const + { + for(int n = 0; n < localLeap.count(); ++n) + { + if(localLeapn->sock == sock) + { + *isLocalLeap = true; + return n; + } + } + + for(int n = 0; n < localStun.count(); ++n) + { + if(localStunn->sock == sock) + { + *isLocalLeap = false; + return n; + } + } + + return -1; + } + + void tryStun(int at) + { + LocalTransport *lt = localStunat; + + bool atLeastOne = false; + if(useStunBind && !config.stunBindAddr.isNull()) + { + atLeastOne = true; + lt->sock->setStunBindService(config.stunBindAddr, config.stunBindPort); + } + if(useStunRelayUdp && !config.stunRelayUdpAddr.isNull() && !config.stunRelayUdpUser.isEmpty()) + { + atLeastOne = true; + lt->sock->setStunRelayService(config.stunRelayUdpAddr, config.stunRelayUdpPort, config.stunRelayUdpUser, config.stunRelayUdpPass); + } + + Q_ASSERT(atLeastOne); + + lt->stun_started = true; + lt->sock->stunStart(); + } + + void ensureExt(LocalTransport *lt, int addrAt) + { + if(!lt->extAddr.isNull() && !lt->ext_finished) + { + CandidateInfo ci; + ci.addr.addr = lt->extAddr; + ci.addr.port = lt->sock->localPort(); + ci.type = ServerReflexiveType; + ci.componentId = id; + ci.priority = choose_default_priority(ci.type, 65535 - addrAt, lt->isVpn, ci.componentId); + ci.base.addr = lt->sock->localAddress(); + ci.base.port = lt->sock->localPort(); + ci.network = lt->network; + + Candidate c; + c.id = getId(); + c.info = ci; + c.iceTransport = lt->sock; + c.path = 0; + + localCandidates += c; + lt->ext_finished = true; + + emit q->candidateAdded(c); + } + } + + void removeLocalCandidates(const IceTransport *sock) + { + ObjectSessionWatcher watch(&sess); + + for(int n = 0; n < localCandidates.count(); ++n) + { + Candidate &c = localCandidatesn; + + if(c.iceTransport == sock) + { + Candidate tmp = localCandidates.takeAt(n); + --n; // adjust position + + channelPeers.remove(tmp.id); + + emit q->candidateRemoved(tmp); + if(!watch.isValid()) + return; + } + } + } + + bool allStopped() const + { + if(localLeap.isEmpty() && localStun.isEmpty() && !tt) + return true; + else + return false; + } + + void tryStopped() + { + if(allStopped()) + postStop(); + } + +private slots: + void doExt() + { + if(stopping) + return; + + ObjectSessionWatcher watch(&sess); + + foreach(LocalTransport *lt, localLeap) + { + if(lt->started) + { + int addrAt = findLocalAddr(lt->addr); + Q_ASSERT(addrAt != -1); + + ensureExt(lt, addrAt); + if(!watch.isValid()) + return; + } + } + } + + void postStop() + { + stopping = false; + + emit q->stopped(); + } + + void lt_started() + { + IceLocalTransport *sock = (IceLocalTransport *)sender(); + bool isLocalLeap = false; + int at = findLocalTransport(sock, &isLocalLeap); + Q_ASSERT(at != -1); + + LocalTransport *lt; + if(isLocalLeap) + lt = localLeapat; + else + lt = localStunat; + + lt->started = true; + + int addrAt = findLocalAddr(lt->addr); + Q_ASSERT(addrAt != -1); + + ObjectSessionWatcher watch(&sess); + + if(useLocal && isLocalLeap) + { + CandidateInfo ci; + ci.addr.addr = lt->sock->localAddress(); + ci.addr.port = lt->sock->localPort(); + ci.type = HostType; + ci.componentId = id; + ci.priority = choose_default_priority(ci.type, 65535 - addrAt, lt->isVpn, ci.componentId); + ci.base = ci.addr; + ci.network = lt->network; + + Candidate c; + c.id = getId(); + c.info = ci; + c.iceTransport = sock; + c.path = 0; + + localCandidates += c; + + emit q->candidateAdded(c); + if(!watch.isValid()) + return; + + ensureExt(lt, addrAt); + if(!watch.isValid()) + return; + } + + if(!isLocalLeap && !lt->stun_started) + tryStun(at); + + bool allFinished = true; + foreach(const LocalTransport *lt, localLeap) + { + if(!lt->started) + { + allFinished = false; + break; + } + } + if(allFinished) + { + foreach(const LocalTransport *lt, localStun) + { + if(!lt->started) + { + allFinished = false; + break; + } + } + } + + if(allFinished && !local_finished) + { + local_finished = true; + emit q->localFinished(); + } + } + + void lt_stopped() + { + IceLocalTransport *sock = (IceLocalTransport *)sender(); + bool isLocalLeap = false; + int at = findLocalTransport(sock, &isLocalLeap); + Q_ASSERT(at != -1); + + LocalTransport *lt; + if(isLocalLeap) + lt = localLeapat; + else + lt = localStunat; + + ObjectSessionWatcher watch(&sess); + + removeLocalCandidates(lt->sock); + if(!watch.isValid()) + return; + + delete lt->sock; + lt->sock = 0; + + if(isLocalLeap) + { + if(lt->borrowedSocket) + portReserver->returnSockets(QList<QUdpSocket*>() << lt->qsock); + else + lt->qsock->deleteLater(); + + delete lt; + localLeap.removeAt(at); + } + else + { + delete lt; + localStun.removeAt(at); + } + + tryStopped(); + } + + void lt_addressesChanged() + { + IceLocalTransport *sock = (IceLocalTransport *)sender(); + bool isLocalLeap = false; + int at = findLocalTransport(sock, &isLocalLeap); + Q_ASSERT(at != -1); + + // leap does not use stun, so we should not get this signal + Q_ASSERT(!isLocalLeap); + + LocalTransport *lt = localStunat; + + int addrAt = findLocalAddr(lt->addr); + Q_ASSERT(addrAt != -1); + + ObjectSessionWatcher watch(&sess); + + if(useStunBind && !lt->sock->serverReflexiveAddress().isNull() && !lt->stun_finished) + { + // automatically assign ext to related leaps, if possible + foreach(LocalTransport *i, localLeap) + { + if(i->extAddr.isNull() && i->sock->localAddress() == lt->sock->localAddress()) + { + i->extAddr = lt->sock->serverReflexiveAddress(); + if(i->started) + { + ensureExt(i, addrAt); + if(!watch.isValid()) + return; + } + } + } + + CandidateInfo ci; + ci.addr.addr = lt->sock->serverReflexiveAddress(); + ci.addr.port = lt->sock->serverReflexivePort(); + ci.type = ServerReflexiveType; + ci.componentId = id; + ci.priority = choose_default_priority(ci.type, 65535 - addrAt, lt->isVpn, ci.componentId); + // stun is only used on non-leap sockets, but we don't + // announce non-leap local candidates, so make the + // base the same as the srflx + //ci.base.addr = lt->sock->localAddress(); + //ci.base.port = lt->sock->localPort(); + ci.base = ci.addr; + ci.network = lt->network; + + Candidate c; + c.id = getId(); + c.info = ci; + c.iceTransport = sock; + c.path = 0; + + localCandidates += c; + lt->stun_finished = true; + + emit q->candidateAdded(c); + if(!watch.isValid()) + return; + } + + if(!lt->sock->relayedAddress().isNull() && !lt->turn_finished) + { + CandidateInfo ci; + ci.addr.addr = lt->sock->relayedAddress(); + ci.addr.port = lt->sock->relayedPort(); + ci.type = RelayedType; + ci.componentId = id; + ci.priority = choose_default_priority(ci.type, 65535 - addrAt, lt->isVpn, ci.componentId); + ci.base.addr = lt->sock->serverReflexiveAddress(); + ci.base.port = lt->sock->serverReflexivePort(); + ci.network = lt->network; + + Candidate c; + c.id = getId(); + c.info = ci; + c.iceTransport = sock; + c.path = 1; + + localCandidates += c; + lt->turn_finished = true; + + emit q->candidateAdded(c); + } + } + + void lt_error(int e) + { + Q_UNUSED(e); + + IceLocalTransport *sock = (IceLocalTransport *)sender(); + bool isLocalLeap = false; + int at = findLocalTransport(sock, &isLocalLeap); + Q_ASSERT(at != -1); + + LocalTransport *lt; + if(isLocalLeap) + lt = localLeapat; + else + lt = localStunat; + + ObjectSessionWatcher watch(&sess); + + removeLocalCandidates(lt->sock); + if(!watch.isValid()) + return; + + delete lt->sock; + lt->sock = 0; + + if(isLocalLeap) + { + if(lt->borrowedSocket) + portReserver->returnSockets(QList<QUdpSocket*>() << lt->qsock); + else + lt->qsock->deleteLater(); + + delete lt; + localLeap.removeAt(at); + } + else + { + delete lt; + localStun.removeAt(at); + } + } + + void lt_debugLine(const QString &line) + { + emit q->debugLine(line); + } + + void tt_started() + { + // lower priority by making it seem like the last nic + int addrAt = 1024; + + CandidateInfo ci; + ci.addr.addr = tt->relayedAddress(); + ci.addr.port = tt->relayedPort(); + ci.type = RelayedType; + ci.componentId = id; + ci.priority = choose_default_priority(ci.type, 65535 - addrAt, false, ci.componentId); + ci.base = ci.addr; + ci.network = 0; // not relevant + + Candidate c; + c.id = getId(); + c.info = ci; + c.iceTransport = tt; + c.path = 0; + + localCandidates += c; + + emit q->candidateAdded(c); + } + + void tt_stopped() + { + ObjectSessionWatcher watch(&sess); + + removeLocalCandidates(tt); + if(!watch.isValid()) + return; + + delete tt; + tt = 0; + + tryStopped(); + } + + void tt_error(int e) + { + Q_UNUSED(e); + + ObjectSessionWatcher watch(&sess); + + removeLocalCandidates(tt); + if(!watch.isValid()) + return; + + delete tt; + tt = 0; + } + + void tt_debugLine(const QString &line) + { + emit q->debugLine(line); + } +}; + +IceComponent::IceComponent(int id, QObject *parent) : + QObject(parent) +{ + d = new Private(this); + d->id = id; +} + +IceComponent::~IceComponent() +{ + delete d; +} + +int IceComponent::id() const +{ + return d->id; +} + +void IceComponent::setClientSoftwareNameAndVersion(const QString &str) +{ + d->clientSoftware = str; +} + +void IceComponent::setProxy(const TurnClient::Proxy &proxy) +{ + d->proxy = proxy; +} + +void IceComponent::setPortReserver(UdpPortReserver *portReserver) +{ + d->portReserver = portReserver; +} + +void IceComponent::setLocalAddresses(const QList<Ice176::LocalAddress> &addrs) +{ + d->pending.localAddrs = addrs; +} + +void IceComponent::setExternalAddresses(const QList<Ice176::ExternalAddress> &addrs) +{ + d->pending.extAddrs = addrs; +} + +void IceComponent::setStunBindService(const QHostAddress &addr, int port) +{ + d->pending.stunBindAddr = addr; + d->pending.stunBindPort = port; +} + +void IceComponent::setStunRelayUdpService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass) +{ + d->pending.stunRelayUdpAddr = addr; + d->pending.stunRelayUdpPort = port; + d->pending.stunRelayUdpUser = user; + d->pending.stunRelayUdpPass = pass; +} + +void IceComponent::setStunRelayTcpService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass) +{ + d->pending.stunRelayTcpAddr = addr; + d->pending.stunRelayTcpPort = port; + d->pending.stunRelayTcpUser = user; + d->pending.stunRelayTcpPass = pass; +} + +void IceComponent::setUseLocal(bool enabled) +{ + d->useLocal = enabled; +} + +void IceComponent::setUseStunBind(bool enabled) +{ + d->useStunBind = enabled; +} + +void IceComponent::setUseStunRelayUdp(bool enabled) +{ + d->useStunRelayUdp = enabled; +} + +void IceComponent::setUseStunRelayTcp(bool enabled) +{ + d->useStunRelayTcp = enabled; +} + +void IceComponent::update(QList<QUdpSocket*> *socketList) +{ + d->update(socketList); +} + +void IceComponent::stop() +{ + d->stop(); +} + +int IceComponent::peerReflexivePriority(const IceTransport *iceTransport, int path) const +{ + return d->peerReflexivePriority(iceTransport, path); +} + +void IceComponent::flagPathAsLowOverhead(int id, const QHostAddress &addr, int port) +{ + return d->flagPathAsLowOverhead(id, addr, port); +} + +void IceComponent::setDebugLevel(DebugLevel level) +{ + d->debugLevel = level; + foreach(const Private::LocalTransport *lt, d->localLeap) + lt->sock->setDebugLevel((IceTransport::DebugLevel)level); + foreach(const Private::LocalTransport *lt, d->localStun) + lt->sock->setDebugLevel((IceTransport::DebugLevel)level); + if(d->tt) + d->tt->setDebugLevel((IceTransport::DebugLevel)level); +} + +} + +#include "icecomponent.moc"
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/icecomponent.h
Added
@@ -0,0 +1,188 @@ +/* + * Copyright (C) 2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef ICECOMPONENT_H +#define ICECOMPONENT_H + +#include <QList> +#include "turnclient.h" +#include "icetransport.h" +#include "ice176.h" + +class QUdpSocket; + +namespace XMPP { + +class UdpPortReserver; + +class IceComponent : public QObject +{ + Q_OBJECT + +public: + enum CandidateType + { + HostType, + PeerReflexiveType, + ServerReflexiveType, + RelayedType + }; + + class TransportAddress + { + public: + QHostAddress addr; + int port; + + TransportAddress() : + port(-1) + { + } + + TransportAddress(const QHostAddress &_addr, int _port) : + addr(_addr), + port(_port) + { + } + + bool operator==(const TransportAddress &other) const + { + if(addr == other.addr && port == other.port) + return true; + else + return false; + } + + inline bool operator!=(const TransportAddress &other) const + { + return !operator==(other); + } + }; + + class CandidateInfo + { + public: + TransportAddress addr; + CandidateType type; + int priority; + QString foundation; + int componentId; + TransportAddress base; + TransportAddress related; + QString id; + int network; + }; + + class Candidate + { + public: + // unique across all candidates within this component + int id; + + // info.id is unset, since it must be unique across all + // components and this class is only aware of itself. it + // is up to the user to create the candidate id. + // info.foundation is also unset, since awareness of all + // components and candidates is needed to calculate it. + CandidateInfo info; + + // note that these may be the same for multiple candidates + IceTransport *iceTransport; + int path; + }; + + enum DebugLevel + { + DL_None, + DL_Info, + DL_Packet + }; + + IceComponent(int id, QObject *parent = 0); + ~IceComponent(); + + int id() const; + + void setClientSoftwareNameAndVersion(const QString &str); + void setProxy(const TurnClient::Proxy &proxy); + + void setPortReserver(UdpPortReserver *portReserver); + + // can be set once, but later changes are ignored + void setLocalAddresses(const QList<Ice176::LocalAddress> &addrs); + + // can be set once, but later changes are ignored. local addresses + // must have been set for this to work + void setExternalAddresses(const QList<Ice176::ExternalAddress> &addrs); + + // can be set at any time, but only once. later changes are ignored + void setStunBindService(const QHostAddress &addr, int port); + void setStunRelayUdpService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass); + void setStunRelayTcpService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass); + + // these all start out enabled, but can be disabled for diagnostic + // purposes + void setUseLocal(bool enabled); + void setUseStunBind(bool enabled); + void setUseStunRelayUdp(bool enabled); + void setUseStunRelayTcp(bool enabled); + + // if socketList is not null then port reserver must be set + void update(QList<QUdpSocket*> *socketList = 0); + void stop(); + + // prflx priority to use when replying from this transport/path + int peerReflexivePriority(const IceTransport *iceTransport, int path) const; + + void flagPathAsLowOverhead(int id, const QHostAddress &addr, int port); + + void setDebugLevel(DebugLevel level); + +signals: + // this is emitted in the same pass of the eventloop that a + // transport/path becomes ready + void candidateAdded(const XMPP::IceComponent::Candidate &c); + + // this is emitted just before a transport/path will be deleted + void candidateRemoved(const XMPP::IceComponent::Candidate &c); + + // indicates all the initial HostType candidates have been pushed. + // note that it is possible there are no HostType candidates. + void localFinished(); + + void stopped(); + + // reports debug of iceTransports as well. not DOR-SS/DS safe + void debugLine(const QString &line); + +private: + class Private; + friend class Private; + Private *d; +}; + +inline uint qHash(const XMPP::IceComponent::TransportAddress &key) +{ + return ::qHash(key.addr) ^ ::qHash(key.port); +} + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/icecomponent_p.h
Added
@@ -0,0 +1,29 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ICECOMPONENT_P_H +#define ICECOMPONENT_P_H + +#endif // ICECOMPONENT_P_H
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/icelocaltransport.cpp
Added
@@ -0,0 +1,888 @@ +/* + * Copyright (C) 2009,2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "icelocaltransport.h" + +#include <QHostAddress> +#include <QUdpSocket> +#include <QtCrypto> +#include "objectsession.h" +#include "stunmessage.h" +#include "stuntransaction.h" +#include "stunbinding.h" +#include "stunallocate.h" +#include "turnclient.h" + +// don't queue more incoming packets than this per transmit path +#define MAX_PACKET_QUEUE 64 + +namespace XMPP { + +enum +{ + Direct, + Relayed +}; + +//---------------------------------------------------------------------------- +// SafeUdpSocket +//---------------------------------------------------------------------------- +// DOR-safe wrapper for QUdpSocket +class SafeUdpSocket : public QObject +{ + Q_OBJECT + +private: + ObjectSession sess; + QUdpSocket *sock; + int writtenCount; + +public: + SafeUdpSocket(QUdpSocket *_sock, QObject *parent = 0) : + QObject(parent), + sess(this), + sock(_sock) + { + sock->setParent(this); + connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); + connect(sock, SIGNAL(bytesWritten(qint64)), SLOT(sock_bytesWritten(qint64))); + + writtenCount = 0; + } + + ~SafeUdpSocket() + { + if(sock) + { + QUdpSocket *out = release(); + out->deleteLater(); + } + } + + QUdpSocket *release() + { + sock->disconnect(this); + sock->setParent(0); + QUdpSocket *out = sock; + sock = 0; + return out; + } + + QHostAddress localAddress() const + { + return sock->localAddress(); + } + + quint16 localPort() const + { + return sock->localPort(); + } + + bool hasPendingDatagrams() const + { + return sock->hasPendingDatagrams(); + } + + QByteArray readDatagram(QHostAddress *address = 0, quint16 *port = 0) + { + if(!sock->hasPendingDatagrams()) + return QByteArray(); + + QByteArray buf; + buf.resize(sock->pendingDatagramSize()); + sock->readDatagram(buf.data(), buf.size(), address, port); + return buf; + } + + void writeDatagram(const QByteArray &buf, const QHostAddress &address, quint16 port) + { + sock->writeDatagram(buf, address, port); + } + +signals: + void readyRead(); + void datagramsWritten(int count); + +private slots: + void sock_readyRead() + { + emit readyRead(); + } + + void sock_bytesWritten(qint64 bytes) + { + Q_UNUSED(bytes); + + ++writtenCount; + sess.deferExclusive(this, "processWritten"); + } + + void processWritten() + { + int count = writtenCount; + writtenCount = 0; + + emit datagramsWritten(count); + } +}; + +//---------------------------------------------------------------------------- +// IceLocalTransport +//---------------------------------------------------------------------------- +class IceLocalTransport::Private : public QObject +{ + Q_OBJECT + +public: + class WriteItem + { + public: + enum Type + { + Direct, + Pool, + Turn + }; + + Type type; + QHostAddress addr; + int port; + }; + + class Written + { + public: + QHostAddress addr; + int port; + int count; + }; + + class Datagram + { + public: + QHostAddress addr; + int port; + QByteArray buf; + }; + + IceLocalTransport *q; + ObjectSession sess; + QUdpSocket *extSock; + SafeUdpSocket *sock; + StunTransactionPool *pool; + StunBinding *stunBinding; + TurnClient *turn; + bool turnActivated; + QHostAddress addr; + int port; + QHostAddress refAddr; + int refPort; + QHostAddress relAddr; + int relPort; + QHostAddress stunBindAddr; + int stunBindPort; + QHostAddress stunRelayAddr; + int stunRelayPort; + QString stunUser; + QCA::SecureArray stunPass; + QString clientSoftware; + QList<Datagram> in; + QList<Datagram> inRelayed; + QList<WriteItem> pendingWrites; + int retryCount; + bool stopping; + int debugLevel; + + Private(IceLocalTransport *_q) : + QObject(_q), + q(_q), + sess(this), + extSock(0), + sock(0), + pool(0), + stunBinding(0), + turn(0), + turnActivated(false), + port(-1), + refPort(-1), + relPort(-1), + retryCount(0), + stopping(false), + debugLevel(IceTransport::DL_None) + { + } + + ~Private() + { + reset(); + } + + void reset() + { + sess.reset(); + + delete stunBinding; + stunBinding = 0; + + delete turn; + turn = 0; + turnActivated = false; + + if(sock) + { + if(extSock) + { + sock->release(); + extSock = 0; + } + + delete sock; + sock = 0; + } + + addr = QHostAddress(); + port = -1; + + refAddr = QHostAddress(); + refPort = -1; + + relAddr = QHostAddress(); + relPort = -1; + + in.clear(); + inRelayed.clear(); + pendingWrites.clear(); + + retryCount = 0; + stopping = false; + } + + void start() + { + Q_ASSERT(!sock); + + sess.defer(this, "postStart"); + } + + void stop() + { + Q_ASSERT(sock); + Q_ASSERT(!stopping); + + stopping = true; + + if(turn) + turn->close(); + else + sess.defer(this, "postStop"); + } + + void stunStart() + { + Q_ASSERT(!pool); + + pool = new StunTransactionPool(StunTransaction::Udp, this); + pool->setDebugLevel((StunTransactionPool::DebugLevel)debugLevel); + connect(pool, SIGNAL(outgoingMessage(const QByteArray &, const QHostAddress &, int)), SLOT(pool_outgoingMessage(const QByteArray &, const QHostAddress &, int))); + connect(pool, SIGNAL(needAuthParams()), SLOT(pool_needAuthParams())); + connect(pool, SIGNAL(debugLine(const QString &)), SLOT(pool_debugLine(const QString &))); + + pool->setLongTermAuthEnabled(true); + if(!stunUser.isEmpty()) + { + pool->setUsername(stunUser); + pool->setPassword(stunPass); + } + + if(!stunBindAddr.isNull()) + { + stunBinding = new StunBinding(pool); + connect(stunBinding, SIGNAL(success()), SLOT(binding_success())); + connect(stunBinding, SIGNAL(error(XMPP::StunBinding::Error)), SLOT(binding_error(XMPP::StunBinding::Error))); + stunBinding->start(stunBindAddr, stunBindPort); + } + + if(!stunRelayAddr.isNull()) + { + do_turn(); + } + } + + void do_turn() + { + turn = new TurnClient(this); + turn->setDebugLevel((TurnClient::DebugLevel)debugLevel); + connect(turn, SIGNAL(connected()), SLOT(turn_connected())); + connect(turn, SIGNAL(tlsHandshaken()), SLOT(turn_tlsHandshaken())); + connect(turn, SIGNAL(closed()), SLOT(turn_closed())); + connect(turn, SIGNAL(activated()), SLOT(turn_activated())); + connect(turn, SIGNAL(packetsWritten(int, const QHostAddress &, int)), SLOT(turn_packetsWritten(int, const QHostAddress &, int))); + connect(turn, SIGNAL(error(XMPP::TurnClient::Error)), SLOT(turn_error(XMPP::TurnClient::Error))); + connect(turn, SIGNAL(outgoingDatagram(const QByteArray &)), SLOT(turn_outgoingDatagram(const QByteArray &))); + connect(turn, SIGNAL(debugLine(const QString &)), SLOT(turn_debugLine(const QString &))); + + turn->setClientSoftwareNameAndVersion(clientSoftware); + + turn->connectToHost(pool, stunRelayAddr, stunRelayPort); + } + +private: + // note: emits signal on error + QUdpSocket *createSocket() + { + QUdpSocket *qsock = new QUdpSocket(this); + if(!qsock->bind(addr, 0)) + { + delete qsock; + emit q->error(IceLocalTransport::ErrorBind); + return 0; + } + + return qsock; + } + + void prepareSocket() + { + addr = sock->localAddress(); + port = sock->localPort(); + + connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); + connect(sock, SIGNAL(datagramsWritten(int)), SLOT(sock_datagramsWritten(int))); + } + + // return true if we are retrying, false if we should error out + bool handleRetry() + { + // don't allow retrying if activated or stopping) + if(turnActivated || stopping) + return false; + + ++retryCount; + if(retryCount < 3) + { + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine("retrying..."); + + delete sock; + sock = 0; + + // to receive this error, it is a Relay, so change + // the mode + //stunType = IceLocalTransport::Relay; + + QUdpSocket *qsock = createSocket(); + if(!qsock) + { + // signal emitted in this case. bail. + // (return true so caller takes no action) + return true; + } + + sock = new SafeUdpSocket(qsock, this); + + prepareSocket(); + + refAddr = QHostAddress(); + refPort = -1; + + relAddr = QHostAddress(); + relPort = -1; + + do_turn(); + + // tell the world that our local address probably + // changed, and that we lost our reflexive address + emit q->addressesChanged(); + return true; + } + + return false; + } + + // return true if data packet, false if pool or nothing + bool processIncomingStun(const QByteArray &buf, const QHostAddress &fromAddr, int fromPort, Datagram *dg) + { + QByteArray data; + QHostAddress dataAddr; + int dataPort; + + bool notStun; + if(!pool->writeIncomingMessage(buf, ¬Stun, fromAddr, fromPort) && turn) + { + data = turn->processIncomingDatagram(buf, notStun, &dataAddr, &dataPort); + if(!data.isNull()) + { + dg->addr = dataAddr; + dg->port = dataPort; + dg->buf = data; + return true; + } + else + { + if(debugLevel >= IceTransport::DL_Packet) + emit q->debugLine("Warning: server responded with what doesn't seem to be a STUN or data packet, skipping."); + } + } + + return false; + } + +private slots: + void postStart() + { + if(stopping) + return; + + if(extSock) + { + sock = new SafeUdpSocket(extSock, this); + } + else + { + QUdpSocket *qsock = createSocket(); + if(!qsock) + { + // signal emitted in this case. bail + return; + } + + sock = new SafeUdpSocket(qsock, this); + } + + prepareSocket(); + + emit q->started(); + } + + void postStop() + { + reset(); + emit q->stopped(); + } + + void sock_readyRead() + { + ObjectSessionWatcher watch(&sess); + + QList<Datagram> dreads; + QList<Datagram> rreads; + + while(sock->hasPendingDatagrams()) + { + QHostAddress from; + quint16 fromPort; + + Datagram dg; + + QByteArray buf = sock->readDatagram(&from, &fromPort); + if((from == stunBindAddr && fromPort == stunBindPort) || (from == stunRelayAddr && fromPort == stunRelayPort)) + { + bool haveData = processIncomingStun(buf, from, fromPort, &dg); + + // processIncomingStun could cause signals to + // emit. for example, stopped() + if(!watch.isValid()) + return; + + if(haveData) + rreads += dg; + } + else + { + dg.addr = from; + dg.port = fromPort; + dg.buf = buf; + dreads += dg; + } + } + + if(dreads.count() > 0) + { + in += dreads; + emit q->readyRead(Direct); + if(!watch.isValid()) + return; + } + + if(rreads.count() > 0) + { + inRelayed += rreads; + emit q->readyRead(Relayed); + } + } + + void sock_datagramsWritten(int count) + { + QList<Written> dwrites; + int twrites = 0; + + while(count > 0) + { + Q_ASSERT(!pendingWrites.isEmpty()); + WriteItem wi = pendingWrites.takeFirst(); + --count; + + if(wi.type == WriteItem::Direct) + { + int at = -1; + for(int n = 0; n < dwrites.count(); ++n) + { + if(dwritesn.addr == wi.addr && dwritesn.port == wi.port) + { + at = n; + break; + } + } + + if(at != -1) + { + ++dwritesat.count; + } + else + { + Written wr; + wr.addr = wi.addr; + wr.port = wi.port; + wr.count = 1; + dwrites += wr; + } + } + else if(wi.type == WriteItem::Turn) + ++twrites; + } + + if(dwrites.isEmpty() && twrites == 0) + return; + + ObjectSessionWatcher watch(&sess); + + if(!dwrites.isEmpty()) + { + foreach(const Written &wr, dwrites) + { + emit q->datagramsWritten(Direct, wr.count, wr.addr, wr.port); + if(!watch.isValid()) + return; + } + } + + if(twrites > 0) + { + // note: this will invoke turn_packetsWritten() + turn->outgoingDatagramsWritten(twrites); + } + } + + void pool_outgoingMessage(const QByteArray &packet, const QHostAddress &toAddress, int toPort) + { + // warning: read StunTransactionPool docs before modifying + // this function + + WriteItem wi; + wi.type = WriteItem::Pool; + pendingWrites += wi; + sock->writeDatagram(packet, toAddress, toPort); + } + + void pool_needAuthParams() + { + // we can get this signal if the user did not provide + // creds to us. however, since this class doesn't support + // prompting just continue on as if we had a blank + // user/pass + pool->continueAfterParams(); + } + + void pool_debugLine(const QString &line) + { + emit q->debugLine(line); + } + + void binding_success() + { + refAddr = stunBinding->reflexiveAddress(); + refPort = stunBinding->reflexivePort(); + + delete stunBinding; + stunBinding = 0; + + emit q->addressesChanged(); + } + + void binding_error(XMPP::StunBinding::Error e) + { + Q_UNUSED(e); + + delete stunBinding; + stunBinding = 0; + + // don't report any error + //if(stunType == IceLocalTransport::Basic || (stunType == IceLocalTransport::Auto && !turn)) + // emit q->addressesChanged(); + } + + void turn_connected() + { + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine("turn_connected"); + } + + void turn_tlsHandshaken() + { + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine("turn_tlsHandshaken"); + } + + void turn_closed() + { + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine("turn_closed"); + + delete turn; + turn = 0; + turnActivated = false; + + postStop(); + } + + void turn_activated() + { + StunAllocate *allocate = turn->stunAllocate(); + + // take reflexive address from TURN only if we are not using a + // separate STUN server + if(stunBindAddr.isNull() || stunBindAddr == stunRelayAddr) + { + refAddr = allocate->reflexiveAddress(); + refPort = allocate->reflexivePort(); + } + + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine(QString("Server says we are ") + allocate->reflexiveAddress().toString() + ';' + QString::number(allocate->reflexivePort())); + + relAddr = allocate->relayedAddress(); + relPort = allocate->relayedPort(); + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine(QString("Server relays via ") + relAddr.toString() + ';' + QString::number(relPort)); + + turnActivated = true; + + emit q->addressesChanged(); + } + + void turn_packetsWritten(int count, const QHostAddress &addr, int port) + { + emit q->datagramsWritten(Relayed, count, addr, port); + } + + void turn_error(XMPP::TurnClient::Error e) + { + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine(QString("turn_error: ") + turn->errorString()); + + delete turn; + turn = 0; + bool wasActivated = turnActivated; + turnActivated = false; + + if(e == TurnClient::ErrorMismatch) + { + if(!extSock && handleRetry()) + return; + } + + // this means our relay died on us. in the future we might + // consider reporting this + if(wasActivated) + return; + + // don't report any error + //if(stunType == IceLocalTransport::Relay || (stunType == IceLocalTransport::Auto && !stunBinding)) + // emit q->addressesChanged(); + } + + void turn_outgoingDatagram(const QByteArray &buf) + { + WriteItem wi; + wi.type = WriteItem::Turn; + pendingWrites += wi; + sock->writeDatagram(buf, stunRelayAddr, stunRelayPort); + } + + void turn_debugLine(const QString &line) + { + emit q->debugLine(line); + } +}; + +IceLocalTransport::IceLocalTransport(QObject *parent) : + IceTransport(parent) +{ + d = new Private(this); +} + +IceLocalTransport::~IceLocalTransport() +{ + delete d; +} + +void IceLocalTransport::setClientSoftwareNameAndVersion(const QString &str) +{ + d->clientSoftware = str; +} + +void IceLocalTransport::start(QUdpSocket *sock) +{ + d->extSock = sock; + d->start(); +} + +void IceLocalTransport::start(const QHostAddress &addr) +{ + d->addr = addr; + d->start(); +} + +void IceLocalTransport::stop() +{ + d->stop(); +} + +void IceLocalTransport::setStunBindService(const QHostAddress &addr, int port) +{ + d->stunBindAddr = addr; + d->stunBindPort = port; +} + +void IceLocalTransport::setStunRelayService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass) +{ + d->stunRelayAddr = addr; + d->stunRelayPort = port; + d->stunUser = user; + d->stunPass = pass; +} + +void IceLocalTransport::stunStart() +{ + d->stunStart(); +} + +QHostAddress IceLocalTransport::localAddress() const +{ + return d->addr; +} + +int IceLocalTransport::localPort() const +{ + return d->port; +} + +QHostAddress IceLocalTransport::serverReflexiveAddress() const +{ + return d->refAddr; +} + +int IceLocalTransport::serverReflexivePort() const +{ + return d->refPort; +} + +QHostAddress IceLocalTransport::relayedAddress() const +{ + return d->relAddr; +} + +int IceLocalTransport::relayedPort() const +{ + return d->relPort; +} + +void IceLocalTransport::addChannelPeer(const QHostAddress &addr, int port) +{ + if(d->turn) + d->turn->addChannelPeer(addr, port); +} + +bool IceLocalTransport::hasPendingDatagrams(int path) const +{ + if(path == Direct) + return !d->in.isEmpty(); + else if(path == Relayed) + return !d->inRelayed.isEmpty(); + else + { + Q_ASSERT(0); + return false; + } +} + +QByteArray IceLocalTransport::readDatagram(int path, QHostAddress *addr, int *port) +{ + QList<Private::Datagram> *in = 0; + if(path == Direct) + in = &d->in; + else if(path == Relayed) + in = &d->inRelayed; + else + Q_ASSERT(0); + + if(!in->isEmpty()) + { + Private::Datagram datagram = in->takeFirst(); + *addr = datagram.addr; + *port = datagram.port; + return datagram.buf; + } + else + return QByteArray(); +} + +void IceLocalTransport::writeDatagram(int path, const QByteArray &buf, const QHostAddress &addr, int port) +{ + if(path == Direct) + { + Private::WriteItem wi; + wi.type = Private::WriteItem::Direct; + wi.addr = addr; + wi.port = port; + d->pendingWrites += wi; + d->sock->writeDatagram(buf, addr, port); + } + else if(path == Relayed) + { + if(d->turn && d->turnActivated) + d->turn->write(buf, addr, port); + } + else + Q_ASSERT(0); +} + +void IceLocalTransport::setDebugLevel(DebugLevel level) +{ + d->debugLevel = level; + if(d->pool) + d->pool->setDebugLevel((StunTransactionPool::DebugLevel)level); + if(d->turn) + d->turn->setDebugLevel((TurnClient::DebugLevel)level); +} + +} + +#include "icelocaltransport.moc"
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/icelocaltransport.h
Added
@@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009,2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef ICELOCALTRANSPORT_H +#define ICELOCALTRANSPORT_H + +#include <QObject> +#include <QByteArray> +#include "icetransport.h" + +class QHostAddress; +class QUdpSocket; + +namespace QCA { + class SecureArray; +} + +namespace XMPP { + +// this class manages a single port on a single interface, including the +// relationship with an associated STUN/TURN server. if TURN is used, this +// class offers two paths (0=direct and 1=relayed), otherwise it offers +// just one path (0=direct) +class IceLocalTransport : public IceTransport +{ + Q_OBJECT + +public: + enum Error + { + ErrorBind = ErrorCustom + }; + + IceLocalTransport(QObject *parent = 0); + ~IceLocalTransport(); + + void setClientSoftwareNameAndVersion(const QString &str); + + // passed socket must already be bind()'ed, don't support + // ErrorMismatch retries + void start(QUdpSocket *sock); + + // bind to this address on a random port, do support ErrorMismatch + // retries + void start(const QHostAddress &addr); + + void setStunBindService(const QHostAddress &addr, int port); + void setStunRelayService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass); + + // obtain relay / reflexive + void stunStart(); + + QHostAddress localAddress() const; + int localPort() const; + + QHostAddress serverReflexiveAddress() const; + int serverReflexivePort() const; + + QHostAddress relayedAddress() const; + int relayedPort() const; + + // reimplemented + virtual void stop(); + virtual bool hasPendingDatagrams(int path) const; + virtual QByteArray readDatagram(int path, QHostAddress *addr, int *port); + virtual void writeDatagram(int path, const QByteArray &buf, const QHostAddress &addr, int port); + virtual void addChannelPeer(const QHostAddress &addr, int port); + virtual void setDebugLevel(DebugLevel level); + +signals: + // may be emitted multiple times. + // if handling internal ErrorMismatch, then local address may change + // and server reflexive address may disappear. + // if start(QUdpSocket*) was used, then ErrorMismatch is not handled, + // and this signal will only be emitted to add addresses + void addressesChanged(); + +private: + class Private; + friend class Private; + Private *d; +}; + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/icetransport.cpp
Added
@@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "icetransport.h" + +namespace XMPP { + +IceTransport::IceTransport(QObject *parent) : + QObject(parent) +{ +} + +IceTransport::~IceTransport() +{ +} + +}
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/icetransport.h
Added
@@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef ICETRANSPORT_H +#define ICETRANSPORT_H + +#include <QObject> +#include <QByteArray> + +class QHostAddress; + +namespace XMPP { + +class IceTransport : public QObject +{ + Q_OBJECT + +public: + enum Error + { + ErrorGeneric, + ErrorCustom + }; + + enum DebugLevel + { + DL_None, + DL_Info, + DL_Packet + }; + + IceTransport(QObject *parent = 0); + ~IceTransport(); + + virtual void stop() = 0; + + virtual bool hasPendingDatagrams(int path) const = 0; + virtual QByteArray readDatagram(int path, QHostAddress *addr, int *port) = 0; + virtual void writeDatagram(int path, const QByteArray &buf, const QHostAddress &addr, int port) = 0; + virtual void addChannelPeer(const QHostAddress &addr, int port) = 0; + + virtual void setDebugLevel(DebugLevel level) = 0; + +signals: + void started(); + void stopped(); + void error(int e); + + void readyRead(int path); + void datagramsWritten(int path, int count, const QHostAddress &addr, int port); + + // not DOR-SS/DS safe + void debugLine(const QString &str); +}; + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/iceturntransport.cpp
Added
@@ -0,0 +1,251 @@ +/* + * Copyright (C) 2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "iceturntransport.h" + +#include <QtCrypto> +#include "stunallocate.h" + +namespace XMPP { + +class IceTurnTransport::Private : public QObject +{ + Q_OBJECT + +public: + IceTurnTransport *q; + int mode; + QHostAddress serverAddr; + int serverPort; + QString relayUser; + QCA::SecureArray relayPass; + QHostAddress relayAddr; + int relayPort; + TurnClient turn; + int turnErrorCode; + int debugLevel; + + Private(IceTurnTransport *_q) : + QObject(_q), + q(_q), + turn(this), + debugLevel(IceTransport::DL_None) + { + connect(&turn, SIGNAL(connected()), SLOT(turn_connected())); + connect(&turn, SIGNAL(tlsHandshaken()), SLOT(turn_tlsHandshaken())); + connect(&turn, SIGNAL(closed()), SLOT(turn_closed())); + connect(&turn, SIGNAL(needAuthParams()), SLOT(turn_needAuthParams())); + connect(&turn, SIGNAL(retrying()), SLOT(turn_retrying())); + connect(&turn, SIGNAL(activated()), SLOT(turn_activated())); + connect(&turn, SIGNAL(readyRead()), SLOT(turn_readyRead())); + connect(&turn, SIGNAL(packetsWritten(int, const QHostAddress &, int)), SLOT(turn_packetsWritten(int, const QHostAddress &, int))); + connect(&turn, SIGNAL(error(XMPP::TurnClient::Error)), SLOT(turn_error(XMPP::TurnClient::Error))); + connect(&turn, SIGNAL(debugLine(const QString &)), SLOT(turn_debugLine(const QString &))); + } + + void start() + { + turn.setUsername(relayUser); + turn.setPassword(relayPass); + turn.connectToHost(serverAddr, serverPort, (TurnClient::Mode)mode); + } + + void stop() + { + turn.close(); + } + +private slots: + void turn_connected() + { + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine("turn_connected"); + } + + void turn_tlsHandshaken() + { + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine("turn_tlsHandshaken"); + } + + void turn_closed() + { + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine("turn_closed"); + + emit q->stopped(); + } + + void turn_needAuthParams() + { + // we can get this signal if the user did not provide + // creds to us. however, since this class doesn't support + // prompting just continue on as if we had a blank + // user/pass + turn.continueAfterParams(); + } + + void turn_retrying() + { + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine("turn_retrying"); + } + + void turn_activated() + { + StunAllocate *allocate = turn.stunAllocate(); + + QHostAddress saddr = allocate->reflexiveAddress(); + quint16 sport = allocate->reflexivePort(); + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine(QString("Server says we are ") + saddr.toString() + ';' + QString::number(sport)); + saddr = allocate->relayedAddress(); + sport = allocate->relayedPort(); + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine(QString("Server relays via ") + saddr.toString() + ';' + QString::number(sport)); + + relayAddr = saddr; + relayPort = sport; + + emit q->started(); + } + + void turn_readyRead() + { + emit q->readyRead(0); + } + + void turn_packetsWritten(int count, const QHostAddress &addr, int port) + { + emit q->datagramsWritten(0, count, addr, port); + } + + void turn_error(XMPP::TurnClient::Error e) + { + if(debugLevel >= IceTransport::DL_Info) + emit q->debugLine(QString("turn_error: ") + turn.errorString()); + + turnErrorCode = e; + emit q->error(IceTurnTransport::ErrorTurn); + } + + void turn_debugLine(const QString &line) + { + emit q->debugLine(line); + } +}; + +IceTurnTransport::IceTurnTransport(QObject *parent) : + IceTransport(parent) +{ + d = new Private(this); +} + +IceTurnTransport::~IceTurnTransport() +{ + delete d; +} + +void IceTurnTransport::setClientSoftwareNameAndVersion(const QString &str) +{ + d->turn.setClientSoftwareNameAndVersion(str); +} + +void IceTurnTransport::setUsername(const QString &user) +{ + d->relayUser = user; +} + +void IceTurnTransport::setPassword(const QCA::SecureArray &pass) +{ + d->relayPass = pass; +} + +void IceTurnTransport::setProxy(const TurnClient::Proxy &proxy) +{ + d->turn.setProxy(proxy); +} + +void IceTurnTransport::start(const QHostAddress &addr, int port, TurnClient::Mode mode) +{ + d->serverAddr = addr; + d->serverPort = port; + d->mode = mode; + d->start(); +} + +QHostAddress IceTurnTransport::relayedAddress() const +{ + return d->relayAddr; +} + +int IceTurnTransport::relayedPort() const +{ + return d->relayPort; +} + +void IceTurnTransport::addChannelPeer(const QHostAddress &addr, int port) +{ + d->turn.addChannelPeer(addr, port); +} + +TurnClient::Error IceTurnTransport::turnErrorCode() const +{ + return (TurnClient::Error)d->turnErrorCode; +} + +void IceTurnTransport::stop() +{ + d->stop(); +} + +bool IceTurnTransport::hasPendingDatagrams(int path) const +{ + Q_ASSERT(path == 0); + Q_UNUSED(path); + + return (d->turn.packetsToRead() > 0 ? true : false); +} + +QByteArray IceTurnTransport::readDatagram(int path, QHostAddress *addr, int *port) +{ + Q_ASSERT(path == 0); + Q_UNUSED(path); + + return d->turn.read(addr, port); +} + +void IceTurnTransport::writeDatagram(int path, const QByteArray &buf, const QHostAddress &addr, int port) +{ + Q_ASSERT(path == 0); + Q_UNUSED(path); + + d->turn.write(buf, addr, port); +} + +void IceTurnTransport::setDebugLevel(DebugLevel level) +{ + d->debugLevel = level; + d->turn.setDebugLevel((TurnClient::DebugLevel)level); +} + +} + +#include "iceturntransport.moc"
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/iceturntransport.h
Added
@@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef ICETURNTRANSPORT_H +#define ICETURNTRANSPORT_H + +#include <QObject> +#include <QByteArray> +#include <QHostAddress> +#include "turnclient.h" +#include "icetransport.h" + +namespace XMPP { + +// for the turn transport, only path 0 is used + +class IceTurnTransport : public IceTransport +{ + Q_OBJECT + +public: + enum Error + { + ErrorTurn = ErrorCustom + }; + + IceTurnTransport(QObject *parent = 0); + ~IceTurnTransport(); + + void setClientSoftwareNameAndVersion(const QString &str); + + // set these before calling start() + void setUsername(const QString &user); + void setPassword(const QCA::SecureArray &pass); + + void setProxy(const TurnClient::Proxy &proxy); + + void start(const QHostAddress &addr, int port, TurnClient::Mode mode = TurnClient::PlainMode); + + QHostAddress relayedAddress() const; + int relayedPort() const; + + TurnClient::Error turnErrorCode() const; + + // reimplemented + virtual void stop(); + virtual bool hasPendingDatagrams(int path) const; + virtual QByteArray readDatagram(int path, QHostAddress *addr, int *port); + virtual void writeDatagram(int path, const QByteArray &buf, const QHostAddress &addr, int port); + virtual void addChannelPeer(const QHostAddress &addr, int port); + virtual void setDebugLevel(DebugLevel level); + +private: + class Private; + friend class Private; + Private *d; +}; + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/objectsession.cpp
Added
@@ -0,0 +1,301 @@ +/* + * Copyright (C) 2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "objectsession.h" + +#include <QList> +#include <QByteArray> +#include <QMetaObject> +#include <QMetaType> +#include <QTimer> + +namespace XMPP { + +class ObjectSessionWatcherPrivate +{ +public: + ObjectSession *sess; +}; + +class ObjectSessionPrivate : public QObject +{ + Q_OBJECT + +public: + ObjectSession *q; + + class MethodCall + { + public: + QObject *obj; + QByteArray method; + class Argument + { + public: + int type; + void *data; + }; + QList<Argument> args; + + MethodCall(QObject *_obj, const char *_method) : + obj(_obj), + method(_method) + { + } + + ~MethodCall() + { + clearArgs(); + } + + void clearArgs() + { + for(int n = 0; n < args.count(); ++n) + QMetaType::destroy(argsn.type, argsn.data); + args.clear(); + } + + bool setArgs(QGenericArgument val0 = QGenericArgument(), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()) + { + const char *arg_name = + { + val0.name(), val1.name(), val2.name(), + val3.name(), val4.name(), val5.name(), + val6.name(), val7.name(), val8.name(), + val9.name() + }; + + void *arg_data = + { + val0.data(), val1.data(), val2.data(), + val3.data(), val4.data(), val5.data(), + val6.data(), val7.data(), val8.data(), + val9.data() + }; + + clearArgs(); + + for(int n = 0; n < 10; ++n) + { + if(arg_namen == 0) + break; + + Argument arg; + arg.type = QMetaType::type(arg_namen); + if(!arg.type) + { + clearArgs(); + return false; + } + + arg.data = QMetaType::construct(arg.type, arg_datan); + args += arg; + } + + return true; + } + }; + + QList<MethodCall*> pendingCalls; + QTimer *callTrigger; + bool paused; + QList<ObjectSessionWatcherPrivate*> watchers; + + ObjectSessionPrivate(ObjectSession *_q) : + QObject(_q), + q(_q), + paused(false) + { + callTrigger = new QTimer(this); + connect(callTrigger, SIGNAL(timeout()), SLOT(doCall())); + callTrigger->setSingleShot(true); + } + + ~ObjectSessionPrivate() + { + invalidateWatchers(); + + callTrigger->disconnect(this); + callTrigger->setParent(0); + callTrigger->deleteLater(); + } + + void addPendingCall(MethodCall *call) + { + pendingCalls += call; + if(!paused && !callTrigger->isActive()) + callTrigger->start(); + } + + bool havePendingCall(QObject *obj, const char *method) const + { + foreach(const MethodCall *call, pendingCalls) + { + if(call->obj == obj && qstrcmp(call->method.data(), method) == 0) + return true; + } + return false; + } + + void invalidateWatchers() + { + for(int n = 0; n < watchers.count(); ++n) + watchersn->sess = 0; + watchers.clear(); + } + +private slots: + void doCall() + { + MethodCall *call = pendingCalls.takeFirst(); + if(!pendingCalls.isEmpty()) + callTrigger->start(); + + Q_ASSERT(call->args.count() <= 10); + + QGenericArgument arg10; + for(int n = 0; n < call->args.count(); ++n) + argn = QGenericArgument(QMetaType::typeName(call->argsn.type), call->argsn.data); + + bool ok; + ok = QMetaObject::invokeMethod(call->obj, call->method.data(), + Qt::DirectConnection, + arg0, arg1, arg2, arg3, arg4, + arg5, arg6, arg7, arg8, arg9); + Q_ASSERT(ok); + + delete call; + } +}; + +ObjectSessionWatcher::ObjectSessionWatcher(ObjectSession *sess) +{ + d = new ObjectSessionWatcherPrivate; + d->sess = sess; + if(d->sess) + d->sess->d->watchers += d; +} + +ObjectSessionWatcher::~ObjectSessionWatcher() +{ + if(d->sess) + d->sess->d->watchers.removeAll(d); + delete d; +} + +bool ObjectSessionWatcher::isValid() const +{ + if(d->sess) + return true; + else + return false; +} + + +ObjectSession::ObjectSession(QObject *parent) : + QObject(parent) +{ + d = new ObjectSessionPrivate(this); +} + +ObjectSession::~ObjectSession() +{ + delete d; +} + +void ObjectSession::reset() +{ + d->invalidateWatchers(); + if(d->callTrigger->isActive()) + d->callTrigger->stop(); + d->pendingCalls.clear(); +} + +bool ObjectSession::isDeferred(QObject *obj, const char *method) +{ + return d->havePendingCall(obj, method); +} + +void ObjectSession::defer(QObject *obj, const char *method, + QGenericArgument val0, + QGenericArgument val1, + QGenericArgument val2, + QGenericArgument val3, + QGenericArgument val4, + QGenericArgument val5, + QGenericArgument val6, + QGenericArgument val7, + QGenericArgument val8, + QGenericArgument val9) +{ + ObjectSessionPrivate::MethodCall *call = new ObjectSessionPrivate::MethodCall(obj, method); + call->setArgs(val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); + d->addPendingCall(call); +} + +void ObjectSession::deferExclusive(QObject *obj, const char *method, + QGenericArgument val0, + QGenericArgument val1, + QGenericArgument val2, + QGenericArgument val3, + QGenericArgument val4, + QGenericArgument val5, + QGenericArgument val6, + QGenericArgument val7, + QGenericArgument val8, + QGenericArgument val9) +{ + if(d->havePendingCall(obj, method)) + return; + + ObjectSessionPrivate::MethodCall *call = new ObjectSessionPrivate::MethodCall(obj, method); + call->setArgs(val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); + d->addPendingCall(call); +} + +void ObjectSession::pause() +{ + Q_ASSERT(!d->paused); + + if(d->callTrigger->isActive()) + d->callTrigger->stop(); + d->paused = true; +} + +void ObjectSession::resume() +{ + Q_ASSERT(d->paused); + + d->paused = false; + if(!d->pendingCalls.isEmpty()) + d->callTrigger->start(); +} + +} + +#include "objectsession.moc"
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/objectsession.h
Added
@@ -0,0 +1,88 @@ +/* + * Copyright (C) 2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef OBJECTSESSION_H +#define OBJECTSESSION_H + +#include <QObject> + +namespace XMPP { + +class ObjectSessionPrivate; +class ObjectSessionWatcherPrivate; + +class ObjectSession : public QObject +{ + Q_OBJECT + +public: + ObjectSession(QObject *parent = 0); + ~ObjectSession(); + + // clear all deferred requests, invalidate watchers + void reset(); + + bool isDeferred(QObject *obj, const char *method); + void defer(QObject *obj, const char *method, + QGenericArgument val0 = QGenericArgument(), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()); + void deferExclusive(QObject *obj, const char *method, + QGenericArgument val0 = QGenericArgument(), + QGenericArgument val1 = QGenericArgument(), + QGenericArgument val2 = QGenericArgument(), + QGenericArgument val3 = QGenericArgument(), + QGenericArgument val4 = QGenericArgument(), + QGenericArgument val5 = QGenericArgument(), + QGenericArgument val6 = QGenericArgument(), + QGenericArgument val7 = QGenericArgument(), + QGenericArgument val8 = QGenericArgument(), + QGenericArgument val9 = QGenericArgument()); + + void pause(); + void resume(); + +private: + friend class ObjectSessionWatcher; + ObjectSessionPrivate *d; +}; + +class ObjectSessionWatcher +{ +public: + ObjectSessionWatcher(ObjectSession *sess); + ~ObjectSessionWatcher(); + + bool isValid() const; + +private: + friend class ObjectSessionPrivate; + ObjectSessionWatcherPrivate *d; +}; + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/servsock.cpp
Added
@@ -0,0 +1,111 @@ +/* + * servsock.cpp - simple wrapper to QServerSocket + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "servsock.h" + +// CS_NAMESPACE_BEGIN + +//---------------------------------------------------------------------------- +// ServSock +//---------------------------------------------------------------------------- +class ServSock::Private +{ +public: + Private() {} + + ServSockSignal *serv; +}; + +ServSock::ServSock(QObject *parent) +:QObject(parent) +{ + d = new Private; + d->serv = 0; +} + +ServSock::~ServSock() +{ + stop(); + delete d; +} + +bool ServSock::isActive() const +{ + return (d->serv ? true: false); +} + +bool ServSock::listen(quint16 port) +{ + stop(); + + d->serv = new ServSockSignal(this); + if(!d->serv->listen(QHostAddress::Any, port)) { + delete d->serv; + d->serv = 0; + return false; + } + connect(d->serv, SIGNAL(connectionReady(int)), SLOT(sss_connectionReady(int))); + + return true; +} + +void ServSock::stop() +{ + delete d->serv; + d->serv = 0; +} + +int ServSock::port() const +{ + if(d->serv) + return d->serv->serverPort(); + else + return -1; +} + +QHostAddress ServSock::address() const +{ + if(d->serv) + return d->serv->serverAddress(); + else + return QHostAddress(); +} + +void ServSock::sss_connectionReady(int s) +{ + connectionReady(s); +} + + +//---------------------------------------------------------------------------- +// ServSockSignal +//---------------------------------------------------------------------------- +ServSockSignal::ServSockSignal(QObject *parent) +:QTcpServer(parent) +{ + setMaxPendingConnections(16); +} + +void ServSockSignal::incomingConnection(int socketDescriptor) +{ + connectionReady(socketDescriptor); +} + +// CS_NAMESPACE_END
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/servsock.h
Added
@@ -0,0 +1,69 @@ +/* + * servsock.h - simple wrapper to QServerSocket + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef CS_SERVSOCK_H +#define CS_SERVSOCK_H + +#include <QtCore> +#include <QtNetwork> + +// CS_NAMESPACE_BEGIN + +class ServSock : public QObject +{ + Q_OBJECT +public: + ServSock(QObject *parent=0); + ~ServSock(); + + bool isActive() const; + bool listen(quint16 port); + void stop(); + int port() const; + QHostAddress address() const; + +signals: + void connectionReady(int); + +private slots: + void sss_connectionReady(int); + +private: + class Private; + Private *d; +}; + +class ServSockSignal : public QTcpServer +{ + Q_OBJECT +public: + ServSockSignal(QObject *parent = 0); + +signals: + void connectionReady(int); + +protected: + // reimplemented + void incomingConnection(int socketDescriptor); +}; + +// CS_NAMESPACE_END + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/socks.cpp
Added
@@ -0,0 +1,1134 @@ +/* + * socks.cpp - SOCKS5 TCP proxy client/server + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "socks.h" + +#include <qhostaddress.h> +#include <qstringlist.h> +#include <qtimer.h> +#include <qpointer.h> +#include <qsocketnotifier.h> +#include <QByteArray> + +#ifdef Q_OS_UNIX +#include <sys/types.h> +#include <netinet/in.h> +#endif + +#ifdef Q_OS_WIN32 +#include <windows.h> +#endif + +#ifdef Q_OS_UNIX +#include <unistd.h> +#include <fcntl.h> +#endif + +#include "servsock.h" +#include "bsocket.h" + +//#define PROX_DEBUG + +#ifdef PROX_DEBUG +#include <stdio.h> +#endif + +// CS_NAMESPACE_BEGIN + +//---------------------------------------------------------------------------- +// SocksUDP +//---------------------------------------------------------------------------- + +class SocksUDP::Private +{ +public: + QUdpSocket *sd; + SocksClient *sc; + QHostAddress routeAddr; + int routePort; + QString host; + int port; +}; + +SocksUDP::SocksUDP(SocksClient *sc, const QString &host, int port, const QHostAddress &routeAddr, int routePort) +:QObject(sc) +{ + d = new Private; + d->sc = sc; + d->sd = new QUdpSocket(this); + connect(d->sd, SIGNAL(readyRead()), SLOT(sd_readyRead())); + d->host = host; + d->port = port; + d->routeAddr = routeAddr; + d->routePort = routePort; +} + +SocksUDP::~SocksUDP() +{ + delete d->sd; + delete d; +} + +void SocksUDP::change(const QString &host, int port) +{ + d->host = host; + d->port = port; +} + +void SocksUDP::write(const QByteArray &data) +{ + d->sd->writeDatagram(data.data(), data.size(), d->routeAddr, d->routePort); +} + +void SocksUDP::sd_activated() +{ + while (d->sd->hasPendingDatagrams()) { + QByteArray datagram; + datagram.resize(d->sd->pendingDatagramSize()); + d->sd->readDatagram(datagram.data(), datagram.size()); + packetReady(datagram); + } +} + +//---------------------------------------------------------------------------- +// SocksClient +//---------------------------------------------------------------------------- +#define REQ_CONNECT 0x01 +#define REQ_BIND 0x02 +#define REQ_UDPASSOCIATE 0x03 + +#define RET_SUCCESS 0x00 +#define RET_UNREACHABLE 0x04 +#define RET_CONNREFUSED 0x05 + +// spc = socks packet client +// sps = socks packet server +// SPCS = socks packet client struct +// SPSS = socks packet server struct + +// Version +static QByteArray spc_set_version() +{ + QByteArray ver; + ver.resize(4); + ver0 = 0x05; // socks version 5 + ver1 = 0x02; // number of methods + ver2 = 0x00; // no-auth + ver3 = 0x02; // username + return ver; +} + +static QByteArray sps_set_version(int method) +{ + QByteArray ver; + ver.resize(2); + ver0 = 0x05; + ver1 = method; + return ver; +} + +struct SPCS_VERSION +{ + unsigned char version; + QByteArray methodList; +}; + +static int spc_get_version(QByteArray *from, SPCS_VERSION *s) +{ + if(from->size() < 1) + return 0; + if(from->at(0) != 0x05) // only SOCKS5 supported + return -1; + if(from->size() < 2) + return 0; + unsigned char mlen = from->at(1); + int num = mlen; + if(num > 16) // who the heck has over 16 auth methods?? + return -1; + if(from->size() < 2 + num) + return 0; + QByteArray a = ByteStream::takeArray(from, 2+num); + s->version = a0; + s->methodList.resize(num); + memcpy(s->methodList.data(), a.data() + 2, num); + return 1; +} + +struct SPSS_VERSION +{ + unsigned char version; + unsigned char method; +}; + +static int sps_get_version(QByteArray *from, SPSS_VERSION *s) +{ + if(from->size() < 2) + return 0; + QByteArray a = ByteStream::takeArray(from, 2); + s->version = a0; + s->method = a1; + return 1; +} + +// authUsername +static QByteArray spc_set_authUsername(const QByteArray &user, const QByteArray &pass) +{ + int len1 = user.length(); + int len2 = pass.length(); + if(len1 > 255) + len1 = 255; + if(len2 > 255) + len2 = 255; + QByteArray a; + a.resize(1+1+len1+1+len2); + a0 = 0x01; // username auth version 1 + a1 = len1; + memcpy(a.data() + 2, user.data(), len1); + a2+len1 = len2; + memcpy(a.data() + 3 + len1, pass.data(), len2); + return a; +} + +static QByteArray sps_set_authUsername(bool success) +{ + QByteArray a; + a.resize(2); + a0 = 0x01; + a1 = success ? 0x00 : 0xff; + return a; +} + +struct SPCS_AUTHUSERNAME +{ + QString user, pass; +}; + +static int spc_get_authUsername(QByteArray *from, SPCS_AUTHUSERNAME *s) +{ + if(from->size() < 1) + return 0; + unsigned char ver = from->at(0); + if(ver != 0x01) + return -1; + if(from->size() < 2) + return 0; + unsigned char ulen = from->at(1); + if((int)from->size() < ulen + 3) + return 0; + unsigned char plen = from->at(ulen+2); + if((int)from->size() < ulen + plen + 3) + return 0; + QByteArray a = ByteStream::takeArray(from, ulen + plen + 3); + + QByteArray user, pass; + user.resize(ulen); + pass.resize(plen); + memcpy(user.data(), a.data()+2, ulen); + memcpy(pass.data(), a.data()+ulen+3, plen); + s->user = QString::fromUtf8(user); + s->pass = QString::fromUtf8(pass); + return 1; +} + +struct SPSS_AUTHUSERNAME +{ + unsigned char version; + bool success; +}; + +static int sps_get_authUsername(QByteArray *from, SPSS_AUTHUSERNAME *s) +{ + if(from->size() < 2) + return 0; + QByteArray a = ByteStream::takeArray(from, 2); + s->version = a0; + s->success = ((char) a1 == 0 ? true: false); + return 1; +} + +// connectRequest +static QByteArray sp_set_request(const QHostAddress &addr, unsigned short port, unsigned char cmd1) +{ + int at = 0; + QByteArray a; + a.resize(4); + aat++ = 0x05; // socks version 5 + aat++ = cmd1; + aat++ = 0x00; // reserved + if(addr.protocol() == QAbstractSocket::IPv4Protocol || addr.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) { + aat++ = 0x01; // address type = ipv4 + quint32 ip4 = htonl(addr.toIPv4Address()); + a.resize(at+4); + memcpy(a.data() + at, &ip4, 4); + at += 4; + } + else { + aat++ = 0x04; + quint8 a616; + QStringList s6 = addr.toString().split(':'); + int at = 0; + quint16 c; + bool ok; + for(QStringList::ConstIterator it = s6.begin(); it != s6.end(); ++it) { + c = (*it).toInt(&ok, 16); + a6at++ = (c >> 8); + a6at++ = c & 0xff; + } + a.resize(at+16); + memcpy(a.data() + at, a6, 16); + at += 16; + } + + // port + a.resize(at+2); + unsigned short p = htons(port); + memcpy(a.data() + at, &p, 2); + + return a; +} + +static QByteArray sp_set_request(const QString &host, quint16 port, unsigned char cmd1) +{ + // detect for IP addresses + QHostAddress addr; + if(addr.setAddress(host)) + return sp_set_request(addr, port, cmd1); + + QByteArray h = host.toUtf8(); + h.truncate(255); + h = QString::fromUtf8(h).toUtf8(); // delete any partial characters? + int hlen = h.length(); + + int at = 0; + QByteArray a; + a.resize(4); + aat++ = 0x05; // socks version 5 + aat++ = cmd1; + aat++ = 0x00; // reserved + aat++ = 0x03; // address type = domain + + // host + a.resize(at+hlen+1); + aat++ = hlen; + memcpy(a.data() + at, h.data(), hlen); + at += hlen; + + // port + a.resize(at+2); + unsigned short p = htons(port); + memcpy(a.data() + at, &p, 2); + + return a; +} + +struct SPS_CONNREQ +{ + unsigned char version; + unsigned char cmd; + int address_type; + QString host; + QHostAddress addr; + quint16 port; +}; + +static int sp_get_request(QByteArray *from, SPS_CONNREQ *s) +{ + int full_len = 4; + if((int)from->size() < full_len) + return 0; + + QString host; + QHostAddress addr; + unsigned char atype = from->at(3); + + if(atype == 0x01) { + full_len += 4; + if((int)from->size() < full_len) + return 0; + quint32 ip4; + memcpy(&ip4, from->data() + 4, 4); + addr.setAddress(ntohl(ip4)); + } + else if(atype == 0x03) { + ++full_len; + if((int)from->size() < full_len) + return 0; + unsigned char host_len = from->at(4); + full_len += host_len; + if((int)from->size() < full_len) + return 0; + QByteArray cs; + cs.resize(host_len); + memcpy(cs.data(), from->data() + 5, host_len); + host = QString::fromLatin1(cs); + } + else if(atype == 0x04) { + full_len += 16; + if((int)from->size() < full_len) + return 0; + quint8 a616; + memcpy(a6, from->data() + 4, 16); + addr.setAddress(a6); + } + + full_len += 2; + if((int)from->size() < full_len) + return 0; + + QByteArray a = ByteStream::takeArray(from, full_len); + + quint16 p; + memcpy(&p, a.data() + full_len - 2, 2); + + s->version = a0; + s->cmd = a1; + s->address_type = atype; + s->host = host; + s->addr = addr; + s->port = ntohs(p); + + return 1; +} + +enum { StepVersion, StepAuth, StepRequest }; + +class SocksClient::Private +{ +public: + Private(SocksClient *_q) : + sock(_q) + { + } + + BSocket sock; + QString host; + int port; + QString user, pass; + QString real_host; + int real_port; + + QByteArray recvBuf; + bool active; + int step; + int authMethod; + bool incoming, waiting; + + QString rhost; + int rport; + + int pending; + + bool udp; + QString udpAddr; + int udpPort; +}; + +SocksClient::SocksClient(QObject *parent) +:ByteStream(parent) +{ + init(); + + d->incoming = false; +} + +SocksClient::SocksClient(int s, QObject *parent) +:ByteStream(parent) +{ + init(); + + d->incoming = true; + d->waiting = true; + d->sock.setSocket(s); +} + +void SocksClient::init() +{ + d = new Private(this); + connect(&d->sock, SIGNAL(connected()), SLOT(sock_connected())); + connect(&d->sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed())); + connect(&d->sock, SIGNAL(delayedCloseFinished()), SLOT(sock_delayedCloseFinished())); + connect(&d->sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); + connect(&d->sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int))); + connect(&d->sock, SIGNAL(error(int)), SLOT(sock_error(int))); + + reset(true); +} + +SocksClient::~SocksClient() +{ + reset(true); + delete d; +} + +void SocksClient::reset(bool clear) +{ + if(d->sock.state() != BSocket::Idle) + d->sock.close(); + if(clear) + clearReadBuffer(); + d->recvBuf.resize(0); + d->active = false; + d->waiting = false; + d->udp = false; + d->pending = 0; +} + +bool SocksClient::isIncoming() const +{ + return d->incoming; +} + +void SocksClient::setAuth(const QString &user, const QString &pass) +{ + d->user = user; + d->pass = pass; +} + +void SocksClient::connectToHost(const QString &proxyHost, int proxyPort, const QString &host, int port, bool udpMode) +{ + reset(true); + + d->host = proxyHost; + d->port = proxyPort; + d->real_host = host; + d->real_port = port; + d->udp = udpMode; + +#ifdef PROX_DEBUG + fprintf(stderr, "SocksClient: Connecting to %s:%d", qPrintable(proxyHost), proxyPort); + if(d->user.isEmpty()) + fprintf(stderr, "\n"); + else + fprintf(stderr, ", auth {%s,%s}\n", qPrintable(d->user), qPrintable(d->pass)); +#endif + d->sock.connectToHost(d->host, d->port); +} + +bool SocksClient::isOpen() const +{ + return d->active; +} + +void SocksClient::close() +{ + d->sock.close(); + if(d->sock.bytesToWrite() == 0) + reset(); +} + +void SocksClient::writeData(const QByteArray &buf) +{ +#ifdef PROX_DEBUG + // show hex + fprintf(stderr, "SocksClient: client write { "); + for(int n = 0; n < (int)buf.size(); ++n) + fprintf(stderr, "%02X ", (unsigned char)bufn); + fprintf(stderr, " } \n"); +#endif + d->pending += buf.size(); + d->sock.write(buf); +} + +void SocksClient::write(const QByteArray &buf) +{ + if(d->active && !d->udp) + d->sock.write(buf); +} + +QByteArray SocksClient::read(int bytes) +{ + return ByteStream::read(bytes); +} + +int SocksClient::bytesAvailable() const +{ + return ByteStream::bytesAvailable(); +} + +int SocksClient::bytesToWrite() const +{ + if(d->active) + return d->sock.bytesToWrite(); + else + return 0; +} + +void SocksClient::sock_connected() +{ +#ifdef PROX_DEBUG + fprintf(stderr, "SocksClient: Connected\n"); +#endif + + d->step = StepVersion; + writeData(spc_set_version()); +} + +void SocksClient::sock_connectionClosed() +{ + if(d->active) { + reset(); + connectionClosed(); + } + else { + error(ErrProxyNeg); + } +} + +void SocksClient::sock_delayedCloseFinished() +{ + if(d->active) { + reset(); + delayedCloseFinished(); + } +} + +void SocksClient::sock_readyRead() +{ + QByteArray block = d->sock.read(); + + if(!d->active) { + if(d->incoming) + processIncoming(block); + else + processOutgoing(block); + } + else { + if(!d->udp) { + appendRead(block); + readyRead(); + } + } +} + +void SocksClient::processOutgoing(const QByteArray &block) +{ +#ifdef PROX_DEBUG + // show hex + fprintf(stderr, "SocksClient: client recv { "); + for(int n = 0; n < (int)block.size(); ++n) + fprintf(stderr, "%02X ", (unsigned char)blockn); + fprintf(stderr, " } \n"); +#endif + ByteStream::appendArray(&d->recvBuf, block); + + if(d->step == StepVersion) { + SPSS_VERSION s; + int r = sps_get_version(&d->recvBuf, &s); + if(r == -1) { + reset(true); + error(ErrProxyNeg); + return; + } + else if(r == 1) { + if(s.version != 0x05 || s.method == 0xff) { +#ifdef PROX_DEBUG + fprintf(stderr, "SocksClient: Method selection failed\n"); +#endif + reset(true); + error(ErrProxyNeg); + return; + } + + QString str; + if(s.method == 0x00) { + str = "None"; + d->authMethod = AuthNone; + } + else if(s.method == 0x02) { + str = "Username/Password"; + d->authMethod = AuthUsername; + } + else { +#ifdef PROX_DEBUG + fprintf(stderr, "SocksClient: Server wants to use unknown method '%02x'\n", s.method); +#endif + reset(true); + error(ErrProxyNeg); + return; + } + + if(d->authMethod == AuthNone) { + // no auth, go straight to the request + do_request(); + } + else if(d->authMethod == AuthUsername) { + d->step = StepAuth; +#ifdef PROX_DEBUG + fprintf(stderr, "SocksClient: Authenticating Username ...\n"); +#endif + writeData(spc_set_authUsername(d->user.toLatin1(), d->pass.toLatin1())); + } + } + } + if(d->step == StepAuth) { + if(d->authMethod == AuthUsername) { + SPSS_AUTHUSERNAME s; + int r = sps_get_authUsername(&d->recvBuf, &s); + if(r == -1) { + reset(true); + error(ErrProxyNeg); + return; + } + else if(r == 1) { + if(s.version != 0x01) { + reset(true); + error(ErrProxyNeg); + return; + } + if(!s.success) { + reset(true); + error(ErrProxyAuth); + return; + } + + do_request(); + } + } + } + else if(d->step == StepRequest) { + SPS_CONNREQ s; + int r = sp_get_request(&d->recvBuf, &s); + if(r == -1) { + reset(true); + error(ErrProxyNeg); + return; + } + else if(r == 1) { + if(s.cmd != RET_SUCCESS) { +#ifdef PROX_DEBUG + fprintf(stderr, "SocksClient: client << Error >> %02x\n", s.cmd); +#endif + reset(true); + if(s.cmd == RET_UNREACHABLE) + error(ErrHostNotFound); + else if(s.cmd == RET_CONNREFUSED) + error(ErrConnectionRefused); + else + error(ErrProxyNeg); + return; + } + +#ifdef PROX_DEBUG + fprintf(stderr, "SocksClient: client << Success >>\n"); +#endif + if(d->udp) { + if(s.address_type == 0x03) + d->udpAddr = s.host; + else + d->udpAddr = s.addr.toString(); + d->udpPort = s.port; + } + + d->active = true; + + QPointer<QObject> self = this; + connected(); + if(!self) + return; + + if(!d->recvBuf.isEmpty()) { + appendRead(d->recvBuf); + d->recvBuf.resize(0); + readyRead(); + } + } + } +} + +void SocksClient::do_request() +{ +#ifdef PROX_DEBUG + fprintf(stderr, "SocksClient: Requesting ...\n"); +#endif + d->step = StepRequest; + int cmd = d->udp ? REQ_UDPASSOCIATE : REQ_CONNECT; + QByteArray buf; + if(!d->real_host.isEmpty()) + buf = sp_set_request(d->real_host, d->real_port, cmd); + else + buf = sp_set_request(QHostAddress(), 0, cmd); + writeData(buf); +} + +void SocksClient::sock_bytesWritten(int x) +{ + int bytes = x; + if(d->pending >= bytes) { + d->pending -= bytes; + bytes = 0; + } + else { + bytes -= d->pending; + d->pending = 0; + } + if(bytes > 0) + bytesWritten(bytes); +} + +void SocksClient::sock_error(int x) +{ + if(d->active) { + reset(); + error(ErrRead); + } + else { + reset(true); + if(x == BSocket::ErrHostNotFound) + error(ErrProxyConnect); + else if(x == BSocket::ErrConnectionRefused) + error(ErrProxyConnect); + else if(x == BSocket::ErrRead) + error(ErrProxyNeg); + } +} + +void SocksClient::serve() +{ + d->waiting = false; + d->step = StepVersion; + continueIncoming(); +} + +void SocksClient::processIncoming(const QByteArray &block) +{ +#ifdef PROX_DEBUG + // show hex + fprintf(stderr, "SocksClient: server recv { "); + for(int n = 0; n < (int)block.size(); ++n) + fprintf(stderr, "%02X ", (unsigned char)blockn); + fprintf(stderr, " } \n"); +#endif + ByteStream::appendArray(&d->recvBuf, block); + + if(!d->waiting) + continueIncoming(); +} + +void SocksClient::continueIncoming() +{ + if(d->recvBuf.isEmpty()) + return; + + if(d->step == StepVersion) { + SPCS_VERSION s; + int r = spc_get_version(&d->recvBuf, &s); + if(r == -1) { + reset(true); + error(ErrProxyNeg); + return; + } + else if(r == 1) { + if(s.version != 0x05) { + reset(true); + error(ErrProxyNeg); + return; + } + + int methods = 0; + for(int n = 0; n < (int)s.methodList.size(); ++n) { + unsigned char c = s.methodListn; + if(c == 0x00) + methods |= AuthNone; + else if(c == 0x02) + methods |= AuthUsername; + } + d->waiting = true; + incomingMethods(methods); + } + } + else if(d->step == StepAuth) { + SPCS_AUTHUSERNAME s; + int r = spc_get_authUsername(&d->recvBuf, &s); + if(r == -1) { + reset(true); + error(ErrProxyNeg); + return; + } + else if(r == 1) { + d->waiting = true; + incomingAuth(s.user, s.pass); + } + } + else if(d->step == StepRequest) { + SPS_CONNREQ s; + int r = sp_get_request(&d->recvBuf, &s); + if(r == -1) { + reset(true); + error(ErrProxyNeg); + return; + } + else if(r == 1) { + d->waiting = true; + if(s.cmd == REQ_CONNECT) { + if(!s.host.isEmpty()) + d->rhost = s.host; + else + d->rhost = s.addr.toString(); + d->rport = s.port; + incomingConnectRequest(d->rhost, d->rport); + } + else if(s.cmd == REQ_UDPASSOCIATE) { + incomingUDPAssociateRequest(); + } + else { + requestDeny(); + return; + } + } + } +} + +void SocksClient::chooseMethod(int method) +{ + if(d->step != StepVersion || !d->waiting) + return; + + unsigned char c; + if(method == AuthNone) { + d->step = StepRequest; + c = 0x00; + } + else { + d->step = StepAuth; + c = 0x02; + } + + // version response + d->waiting = false; + writeData(sps_set_version(c)); + continueIncoming(); +} + +void SocksClient::authGrant(bool b) +{ + if(d->step != StepAuth || !d->waiting) + return; + + if(b) + d->step = StepRequest; + + // auth response + d->waiting = false; + writeData(sps_set_authUsername(b)); + if(!b) { + reset(true); + return; + } + continueIncoming(); +} + +void SocksClient::requestDeny() +{ + if(d->step != StepRequest || !d->waiting) + return; + + // response + d->waiting = false; + writeData(sp_set_request(d->rhost, d->rport, RET_UNREACHABLE)); + reset(true); +} + +void SocksClient::grantConnect() +{ + if(d->step != StepRequest || !d->waiting) + return; + + // response + d->waiting = false; + writeData(sp_set_request(d->rhost, d->rport, RET_SUCCESS)); + d->active = true; +#ifdef PROX_DEBUG + fprintf(stderr, "SocksClient: server << Success >>\n"); +#endif + + if(!d->recvBuf.isEmpty()) { + appendRead(d->recvBuf); + d->recvBuf.resize(0); + readyRead(); + } +} + +void SocksClient::grantUDPAssociate(const QString &relayHost, int relayPort) +{ + if(d->step != StepRequest || !d->waiting) + return; + + // response + d->waiting = false; + writeData(sp_set_request(relayHost, relayPort, RET_SUCCESS)); + d->udp = true; + d->active = true; +#ifdef PROX_DEBUG + fprintf(stderr, "SocksClient: server << Success >>\n"); +#endif + + if(!d->recvBuf.isEmpty()) + d->recvBuf.resize(0); +} + +QHostAddress SocksClient::peerAddress() const +{ + return d->sock.peerAddress(); +} + +quint16 SocksClient::peerPort() const +{ + return d->sock.peerPort(); +} + +QString SocksClient::udpAddress() const +{ + return d->udpAddr; +} + +quint16 SocksClient::udpPort() const +{ + return d->udpPort; +} + +SocksUDP *SocksClient::createUDP(const QString &host, int port, const QHostAddress &routeAddr, int routePort) +{ + return new SocksUDP(this, host, port, routeAddr, routePort); +} + +//---------------------------------------------------------------------------- +// SocksServer +//---------------------------------------------------------------------------- +class SocksServer::Private +{ +public: + Private(SocksServer *_q) : + serv(_q) + { + } + + ServSock serv; + QList<SocksClient*> incomingConns; + QUdpSocket *sd; +}; + +SocksServer::SocksServer(QObject *parent) +:QObject(parent) +{ + d = new Private(this); + d->sd = 0; + connect(&d->serv, SIGNAL(connectionReady(int)), SLOT(connectionReady(int))); +} + +SocksServer::~SocksServer() +{ + stop(); + while (d->incomingConns.count()) { + delete d->incomingConns.takeFirst(); + } + delete d; +} + +bool SocksServer::isActive() const +{ + return d->serv.isActive(); +} + +bool SocksServer::listen(quint16 port, bool udp) +{ + stop(); + if(!d->serv.listen(port)) + return false; + if(udp) { + d->sd = new QUdpSocket(this); + if(!d->sd->bind(QHostAddress::LocalHost, port)) { + delete d->sd; + d->sd = 0; + d->serv.stop(); + return false; + } + connect(d->sd, SIGNAL(readyRead()), SLOT(sd_activated())); + } + return true; +} + +void SocksServer::stop() +{ + delete d->sd; + d->sd = 0; + d->serv.stop(); +} + +int SocksServer::port() const +{ + return d->serv.port(); +} + +QHostAddress SocksServer::address() const +{ + return d->serv.address(); +} + +SocksClient *SocksServer::takeIncoming() +{ + if(d->incomingConns.isEmpty()) + return 0; + + SocksClient *c = d->incomingConns.takeFirst(); + + // we don't care about errors anymore + disconnect(c, SIGNAL(error(int)), this, SLOT(connectionError())); + + // don't serve the connection until the event loop, to give the caller a chance to map signals + QTimer::singleShot(0, c, SLOT(serve())); + + return c; +} + +void SocksServer::writeUDP(const QHostAddress &addr, int port, const QByteArray &data) +{ + if(d->sd) { + d->sd->writeDatagram(data.data(), data.size(), addr, port); + } +} + +void SocksServer::connectionReady(int s) +{ + SocksClient *c = new SocksClient(s, this); + connect(c, SIGNAL(error(int)), this, SLOT(connectionError())); + d->incomingConns.append(c); + incomingReady(); +} + +void SocksServer::connectionError() +{ + SocksClient *c = (SocksClient *)sender(); + d->incomingConns.removeAll(c); + c->deleteLater(); +} + +void SocksServer::sd_activated() +{ + while (d->sd->hasPendingDatagrams()) { + QByteArray datagram; + QHostAddress sender; + quint16 senderPort; + datagram.resize(d->sd->pendingDatagramSize()); + d->sd->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); + incomingUDP(sender.toString(), senderPort, d->sd->peerAddress(), d->sd->peerPort(), datagram); + } +} + +// CS_NAMESPACE_END
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/socks.h
Added
@@ -0,0 +1,160 @@ +/* + * socks.h - SOCKS5 TCP proxy client/server + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef CS_SOCKS_H +#define CS_SOCKS_H + +#include "bytestream.h" + +// CS_NAMESPACE_BEGIN + +class QHostAddress; +class SocksClient; +class SocksServer; + +class SocksUDP : public QObject +{ + Q_OBJECT +public: + ~SocksUDP(); + + void change(const QString &host, int port); + void write(const QByteArray &data); + +signals: + void packetReady(const QByteArray &data); + +private slots: + void sd_activated(); + +private: + class Private; + Private *d; + + friend class SocksClient; + SocksUDP(SocksClient *sc, const QString &host, int port, const QHostAddress &routeAddr, int routePort); +}; + +class SocksClient : public ByteStream +{ + Q_OBJECT +public: + enum Error { ErrConnectionRefused = ErrCustom, ErrHostNotFound, ErrProxyConnect, ErrProxyNeg, ErrProxyAuth }; + enum Method { AuthNone=0x0001, AuthUsername=0x0002 }; + enum Request { ReqConnect, ReqUDPAssociate }; + SocksClient(QObject *parent=0); + SocksClient(int, QObject *parent=0); + ~SocksClient(); + + bool isIncoming() const; + + // outgoing + void setAuth(const QString &user, const QString &pass=""); + void connectToHost(const QString &proxyHost, int proxyPort, const QString &host, int port, bool udpMode=false); + + // incoming + void chooseMethod(int); + void authGrant(bool); + void requestDeny(); + void grantConnect(); + void grantUDPAssociate(const QString &relayHost, int relayPort); + + // from ByteStream + bool isOpen() const; + void close(); + void write(const QByteArray &); + QByteArray read(int bytes=0); + int bytesAvailable() const; + int bytesToWrite() const; + + // remote address + QHostAddress peerAddress() const; + quint16 peerPort() const; + + // udp + QString udpAddress() const; + quint16 udpPort() const; + SocksUDP *createUDP(const QString &host, int port, const QHostAddress &routeAddr, int routePort); + +signals: + // outgoing + void connected(); + + // incoming + void incomingMethods(int); + void incomingAuth(const QString &user, const QString &pass); + void incomingConnectRequest(const QString &host, int port); + void incomingUDPAssociateRequest(); + +private slots: + void sock_connected(); + void sock_connectionClosed(); + void sock_delayedCloseFinished(); + void sock_readyRead(); + void sock_bytesWritten(int); + void sock_error(int); + void serve(); + +private: + class Private; + Private *d; + + void init(); + void reset(bool clear=false); + void do_request(); + void processOutgoing(const QByteArray &); + void processIncoming(const QByteArray &); + void continueIncoming(); + void writeData(const QByteArray &a); +}; + +class SocksServer : public QObject +{ + Q_OBJECT +public: + SocksServer(QObject *parent=0); + ~SocksServer(); + + bool isActive() const; + bool listen(quint16 port, bool udp=false); + void stop(); + int port() const; + QHostAddress address() const; + SocksClient *takeIncoming(); + + void writeUDP(const QHostAddress &addr, int port, const QByteArray &data); + +signals: + void incomingReady(); + void incomingUDP(const QString &host, int port, const QHostAddress &addr, int sourcePort, const QByteArray &data); + +private slots: + void connectionReady(int); + void connectionError(); + void sd_activated(); + +private: + class Private; + Private *d; +}; + +// CS_NAMESPACE_END + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stunallocate.cpp
Added
@@ -0,0 +1,1455 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "stunallocate.h" + +#include <QMetaType> +#include <QHostAddress> +#include <QTimer> +#include <QtCrypto> +#include "objectsession.h" +#include "stunutil.h" +#include "stunmessage.h" +#include "stuntypes.h" +#include "stuntransaction.h" + +// permissions last 5 minutes, update them every 4 minutes +#define PERM_INTERVAL (4 * 60 * 1000) + +// channels last 10 minutes, update them every 9 minutes +#define CHAN_INTERVAL (9 * 60 * 1000) + +namespace XMPP { + +void releaseAndDeleteLater(QObject *owner, QObject *obj) +{ + obj->disconnect(owner); + obj->setParent(0); + obj->deleteLater(); +} + +// return size of channelData packet, or -1 +static int check_channelData(const quint8 *data, int size) +{ + // top two bits are never zero for ChannelData + if((data0 & 0xc0) == 0) + return -1; + + if(size < 4) + return -1; + + quint16 len = StunUtil::read16(data + 2); + if(size - 4 < (int)len) + return -1; + + // data from a stream must be 4 byte aligned + int plen = len; + int remainder = plen % 4; + if(remainder != 0) + plen += (4 - remainder); + + int need = plen + 4; + if(size < need) + return -1; + + return need; +} + +class StunAllocatePermission : public QObject +{ + Q_OBJECT + +public: + QTimer *timer; + StunTransactionPool *pool; + StunTransaction *trans; + QHostAddress stunAddr; + int stunPort; + QHostAddress addr; + bool active; + + enum Error + { + ErrorGeneric, + ErrorProtocol, + ErrorCapacity, + ErrorForbidden, + ErrorRejected, + ErrorTimeout + }; + + StunAllocatePermission(StunTransactionPool *_pool, const QHostAddress &_addr) : + QObject(_pool), + pool(_pool), + trans(0), + addr(_addr), + active(false) + { + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), SLOT(timer_timeout())); + timer->setSingleShot(true); + timer->setInterval(PERM_INTERVAL); + } + + ~StunAllocatePermission() + { + cleanup(); + + releaseAndDeleteLater(this, timer); + } + + void start(const QHostAddress &_addr, int _port) + { + Q_ASSERT(!active); + + stunAddr = _addr; + stunPort = _port; + + doTransaction(); + } + + static StunAllocate::Error errorToStunAllocateError(Error e) + { + switch(e) + { + case ErrorProtocol: + return StunAllocate::ErrorProtocol; + case ErrorCapacity: + return StunAllocate::ErrorCapacity; + case ErrorForbidden: + case ErrorRejected: + return StunAllocate::ErrorRejected; + case ErrorTimeout: + return StunAllocate::ErrorTimeout; + default: + return StunAllocate::ErrorGeneric; + } + } + +signals: + void ready(); + void error(XMPP::StunAllocatePermission::Error e, const QString &reason); + +private: + void cleanup() + { + delete trans; + trans = 0; + + timer->stop(); + + active = false; + } + + void doTransaction() + { + Q_ASSERT(!trans); + trans = new StunTransaction(this); + connect(trans, SIGNAL(createMessage(const QByteArray &)), SLOT(trans_createMessage(const QByteArray &))); + connect(trans, SIGNAL(finished(const XMPP::StunMessage &)), SLOT(trans_finished(const XMPP::StunMessage &))); + connect(trans, SIGNAL(error(XMPP::StunTransaction::Error)), SLOT(trans_error(XMPP::StunTransaction::Error))); + trans->start(pool, stunAddr, stunPort); + } + + void restartTimer() + { + timer->start(); + } + +private slots: + void trans_createMessage(const QByteArray &transactionId) + { + // CreatePermission + StunMessage message; + message.setMethod(StunTypes::CreatePermission); + message.setId((const quint8 *)transactionId.data()); + + QList<StunMessage::Attribute> list; + + // we only do one address per permission request, because + // otherwise if we receive an error it would be ambiguous + // as to which address the error applies to + + { + StunMessage::Attribute a; + a.type = StunTypes::XOR_PEER_ADDRESS; + a.value = StunTypes::createXorPeerAddress(addr, 0, message.magic(), message.id()); + list += a; + } + + message.setAttributes(list); + + trans->setMessage(message); + } + + void trans_finished(const XMPP::StunMessage &response) + { + delete trans; + trans = 0; + + bool err = false; + int code; + QString reason; + if(response.mclass() == StunMessage::ErrorResponse) + { + if(!StunTypes::parseErrorCode(response.attribute(StunTypes::ERROR_CODE), &code, &reason)) + { + cleanup(); + emit error(ErrorProtocol, "Unable to parse ERROR-CODE in error response."); + return; + } + + err = true; + } + + if(err) + { + cleanup(); + + if(code == StunTypes::InsufficientCapacity) + emit error(ErrorCapacity, reason); + else if(code == StunTypes::Forbidden) + emit error(ErrorForbidden, reason); + else + emit error(ErrorRejected, reason); + + return; + } + + restartTimer(); + + if(!active) + { + active = true; + emit ready(); + } + } + + void trans_error(XMPP::StunTransaction::Error e) + { + cleanup(); + + if(e == XMPP::StunTransaction::ErrorTimeout) + emit error(ErrorTimeout, "Request timed out."); + else + emit error(ErrorGeneric, "Generic transaction error."); + } + + void timer_timeout() + { + doTransaction(); + } +}; + +class StunAllocateChannel : public QObject +{ + Q_OBJECT + +public: + QTimer *timer; + StunTransactionPool *pool; + StunTransaction *trans; + QHostAddress stunAddr; + int stunPort; + int channelId; + QHostAddress addr; + int port; + bool active; + + enum Error + { + ErrorGeneric, + ErrorProtocol, + ErrorCapacity, + ErrorForbidden, + ErrorRejected, + ErrorTimeout + }; + + StunAllocateChannel(StunTransactionPool *_pool, int _channelId, const QHostAddress &_addr, int _port) : + QObject(_pool), + pool(_pool), + trans(0), + channelId(_channelId), + addr(_addr), + port(_port), + active(false) + { + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), SLOT(timer_timeout())); + timer->setSingleShot(true); + timer->setInterval(CHAN_INTERVAL); + } + + ~StunAllocateChannel() + { + cleanup(); + + releaseAndDeleteLater(this, timer); + } + + void start(const QHostAddress &_addr, int _port) + { + Q_ASSERT(!active); + + stunAddr = _addr; + stunPort = _port; + + doTransaction(); + } + + static StunAllocate::Error errorToStunAllocateError(Error e) + { + switch(e) + { + case ErrorProtocol: + return StunAllocate::ErrorProtocol; + case ErrorCapacity: + return StunAllocate::ErrorCapacity; + case ErrorForbidden: + case ErrorRejected: + return StunAllocate::ErrorRejected; + case ErrorTimeout: + return StunAllocate::ErrorTimeout; + default: + return StunAllocate::ErrorGeneric; + } + } + +signals: + void ready(); + void error(XMPP::StunAllocateChannel::Error e, const QString &reason); + +private: + void cleanup() + { + delete trans; + trans = 0; + + timer->stop(); + + channelId = -1; + active = false; + } + + void doTransaction() + { + Q_ASSERT(!trans); + trans = new StunTransaction(this); + connect(trans, SIGNAL(createMessage(const QByteArray &)), SLOT(trans_createMessage(const QByteArray &))); + connect(trans, SIGNAL(finished(const XMPP::StunMessage &)), SLOT(trans_finished(const XMPP::StunMessage &))); + connect(trans, SIGNAL(error(XMPP::StunTransaction::Error)), SLOT(trans_error(XMPP::StunTransaction::Error))); + trans->start(pool, stunAddr, stunPort); + } + + void restartTimer() + { + timer->start(); + } + +private slots: + void trans_createMessage(const QByteArray &transactionId) + { + // ChannelBind + StunMessage message; + message.setMethod(StunTypes::ChannelBind); + message.setId((const quint8 *)transactionId.data()); + + QList<StunMessage::Attribute> list; + + { + StunMessage::Attribute a; + a.type = StunTypes::CHANNEL_NUMBER; + a.value = StunTypes::createChannelNumber(channelId); + list += a; + } + + { + StunMessage::Attribute a; + a.type = StunTypes::XOR_PEER_ADDRESS; + a.value = StunTypes::createXorPeerAddress(addr, port, message.magic(), message.id()); + list += a; + } + + message.setAttributes(list); + + trans->setMessage(message); + } + + void trans_finished(const XMPP::StunMessage &response) + { + delete trans; + trans = 0; + + bool err = false; + int code; + QString reason; + if(response.mclass() == StunMessage::ErrorResponse) + { + if(!StunTypes::parseErrorCode(response.attribute(StunTypes::ERROR_CODE), &code, &reason)) + { + cleanup(); + emit error(ErrorProtocol, "Unable to parse ERROR-CODE in error response."); + return; + } + + err = true; + } + + if(err) + { + cleanup(); + + if(code == StunTypes::InsufficientCapacity) + emit error(ErrorCapacity, reason); + else if(code == StunTypes::Forbidden) + emit error(ErrorForbidden, reason); + else + emit error(ErrorRejected, reason); + + return; + } + + restartTimer(); + + if(!active) + { + active = true; + emit ready(); + } + } + + void trans_error(XMPP::StunTransaction::Error e) + { + cleanup(); + + if(e == XMPP::StunTransaction::ErrorTimeout) + emit error(ErrorTimeout, "Request timed out."); + else + emit error(ErrorGeneric, "Generic transaction error."); + } + + void timer_timeout() + { + doTransaction(); + } +}; + +class StunAllocate::Private : public QObject +{ + Q_OBJECT + +public: + enum DontFragmentState + { + DF_Unknown, + DF_Supported, + DF_Unsupported + }; + + enum State + { + Stopped, + Starting, + Started, + Refreshing, + Stopping, + Erroring // like stopping, but emits error when finished + }; + + StunAllocate *q; + ObjectSession sess; + StunTransactionPool *pool; + StunTransaction *trans; + QHostAddress stunAddr; + int stunPort; + State state; + QString errorString; + DontFragmentState dfState; + QString clientSoftware, serverSoftware; + QHostAddress reflexiveAddress, relayedAddress; + int reflexivePort, relayedPort; + StunMessage msg; + int allocateLifetime; + QTimer *allocateRefreshTimer; + QList<StunAllocatePermission*> perms; + QList<StunAllocateChannel*> channels; + QList<QHostAddress> permsOut; + QList<StunAllocate::Channel> channelsOut; + int erroringCode; + QString erroringString; + + Private(StunAllocate *_q) : + QObject(_q), + q(_q), + sess(this), + pool(0), + trans(0), + state(Stopped), + dfState(DF_Unknown), + erroringCode(-1) + { + allocateRefreshTimer = new QTimer(this); + connect(allocateRefreshTimer, SIGNAL(timeout()), SLOT(refresh())); + allocateRefreshTimer->setSingleShot(true); + } + + ~Private() + { + cleanup(); + + releaseAndDeleteLater(this, allocateRefreshTimer); + } + + void start(const QHostAddress &_addr = QHostAddress(), int _port = -1) + { + Q_ASSERT(state == Stopped); + + stunAddr = _addr; + stunPort = _port; + + state = Starting; + doTransaction(); + } + + void stop() + { + // erroring already? no need to do anything + if(state == Erroring) + return; + + Q_ASSERT(state == Started); + + cleanupTasks(); + state = Stopping; + doTransaction(); + } + + void stopWithError(int code, const QString &str) + { + Q_ASSERT(state == Started); + + cleanupTasks(); + erroringCode = code; + erroringString = str; + state = Erroring; + doTransaction(); + } + + void setPermissions(const QList<QHostAddress> &newPerms) + { + // if currently erroring out, skip + if(state == Erroring) + return; + + Q_ASSERT(state == Started); + + int freeCount = 0; + + // removed? + for(int n = 0; n < perms.count(); ++n) + { + bool found = false; + for(int k = 0; k < newPerms.count(); ++k) + { + if(newPermsk == permsn->addr) + { + found = true; + break; + } + } + + if(!found) + { + // delete related channels + for(int j = 0; j < channels.count(); ++j) + { + if(channelsj->addr == permsn->addr) + { + delete channelsj; + channels.removeAt(j); + --j; // adjust position + } + } + + ++freeCount; + + delete permsn; + perms.removeAt(n); + --n; // adjust position + } + } + + if(freeCount > 0) + { + // removals count as a change, so emit the signal + sess.deferExclusive(q, "permissionsChanged"); + + // wake up inactive perms now that we've freed space + for(int n = 0; n < perms.count(); ++n) + { + if(!permsn->active) + permsn->start(stunAddr, stunPort); + } + } + + // added? + for(int n = 0; n < newPerms.count(); ++n) + { + bool found = false; + for(int k = 0; k < perms.count(); ++k) + { + if(permsk->addr == newPermsn) + { + found = true; + break; + } + } + + if(!found) + { + StunAllocatePermission *perm = new StunAllocatePermission(pool, newPermsn); + connect(perm, SIGNAL(ready()), SLOT(perm_ready())); + connect(perm, SIGNAL(error(XMPP::StunAllocatePermission::Error, const QString &)), SLOT(perm_error(XMPP::StunAllocatePermission::Error, const QString &))); + perms += perm; + perm->start(stunAddr, stunPort); + } + } + } + + void setChannels(const QList<StunAllocate::Channel> &newChannels) + { + // if currently erroring out, skip + if(state == Erroring) + return; + + Q_ASSERT(state == Started); + + int freeCount = 0; + + // removed? + for(int n = 0; n < channels.count(); ++n) + { + bool found = false; + for(int k = 0; k < newChannels.count(); ++k) + { + if(newChannelsk.address == channelsn->addr && newChannelsk.port == channelsn->port) + { + found = true; + break; + } + } + + if(!found) + { + ++freeCount; + + delete channelsn; + channels.removeAt(n); + --n; // adjust position + } + } + + if(freeCount > 0) + { + // removals count as a change, so emit the signal + sess.deferExclusive(q, "channelsChanged"); + + // wake up inactive channels now that we've freed space + for(int n = 0; n < channels.count(); ++n) + { + if(!channelsn->active) + { + int channelId = getFreeChannelNumber(); + + // out of channels? give up + if(channelId == -1) + break; + + channelsn->channelId = channelId; + channelsn->start(stunAddr, stunPort); + } + } + } + + // added? + for(int n = 0; n < newChannels.count(); ++n) + { + bool found = false; + for(int k = 0; k < channels.count(); ++k) + { + if(channelsk->addr == newChannelsn.address && channelsk->port == newChannelsn.port) + { + found = true; + break; + } + } + + if(!found) + { + // look up the permission for this channel + int at = -1; + for(int k = 0; k < perms.count(); ++k) + { + if(permsk->addr == newChannelsn.address) + { + at = k; + break; + } + } + + // only install a channel if we have a permission + if(at != -1) + { + int channelId = getFreeChannelNumber(); + + StunAllocateChannel *channel = new StunAllocateChannel(pool, channelId, newChannelsn.address, newChannelsn.port); + connect(channel, SIGNAL(ready()), SLOT(channel_ready())); + connect(channel, SIGNAL(error(XMPP::StunAllocateChannel::Error, const QString &)), SLOT(channel_error(XMPP::StunAllocateChannel::Error, const QString &))); + channels += channel; + + if(channelId != -1) + channel->start(stunAddr, stunPort); + } + } + } + } + + int getFreeChannelNumber() + { + for(int tryId = 0x4000; tryId <= 0x7fff; ++tryId) + { + bool found = false; + for(int n = 0; n < channels.count(); ++n) + { + if(channelsn->channelId == tryId) + { + found = true; + break; + } + } + + if(!found) + return tryId; + } + + return -1; + } + + int getChannel(const QHostAddress &addr, int port) + { + for(int n = 0; n < channels.count(); ++n) + { + if(channelsn->active && channelsn->addr == addr && channelsn->port == port) + return channelsn->channelId; + } + + return -1; + } + + // note that this function works even for inactive channels, so that + // incoming traffic that is received out-of-order with a + // ChannelBind success response is still processable + bool getAddressPort(int channelId, QHostAddress *addr, int *port) + { + for(int n = 0; n < channels.count(); ++n) + { + if(channelsn->channelId == channelId) + { + *addr = channelsn->addr; + *port = channelsn->port; + return true; + } + } + + return false; + } + +private: + void cleanup() + { + sess.reset(); + + cleanupTasks(); + + erroringCode = -1; + erroringString.clear(); + + state = Stopped; + } + + // stop refreshing, permissions, and channelbinds + void cleanupTasks() + { + delete trans; + trans = 0; + + allocateRefreshTimer->stop(); + + qDeleteAll(channels); + channels.clear(); + channelsOut.clear(); + + qDeleteAll(perms); + perms.clear(); + permsOut.clear(); + } + + void doTransaction() + { + Q_ASSERT(!trans); + trans = new StunTransaction(this); + connect(trans, SIGNAL(createMessage(const QByteArray &)), SLOT(trans_createMessage(const QByteArray &))); + connect(trans, SIGNAL(finished(const XMPP::StunMessage &)), SLOT(trans_finished(const XMPP::StunMessage &))); + connect(trans, SIGNAL(error(XMPP::StunTransaction::Error)), SLOT(trans_error(XMPP::StunTransaction::Error))); + trans->start(pool, stunAddr, stunPort); + } + + void restartRefreshTimer() + { + // refresh 1 minute shy of the lifetime + allocateRefreshTimer->start((allocateLifetime - 60) * 1000); + } + + bool updatePermsOut() + { + QList<QHostAddress> newList; + + for(int n = 0; n < perms.count(); ++n) + { + if(permsn->active) + newList += permsn->addr; + } + + if(newList == permsOut) + return false; + + permsOut = newList; + return true; + } + + bool updateChannelsOut() + { + QList<StunAllocate::Channel> newList; + + for(int n = 0; n < channels.count(); ++n) + { + if(channelsn->active) + newList += StunAllocate::Channel(channelsn->addr, channelsn->port); + } + + if(newList == channelsOut) + return false; + + channelsOut = newList; + return true; + } + +private slots: + void refresh() + { + Q_ASSERT(state == Started); + + state = Refreshing; + doTransaction(); + } + + void trans_createMessage(const QByteArray &transactionId) + { + if(state == Starting) + { + // send Allocate request + StunMessage message; + message.setMethod(StunTypes::Allocate); + message.setId((const quint8 *)transactionId.data()); + + QList<StunMessage::Attribute> list; + + if(!clientSoftware.isEmpty()) + { + StunMessage::Attribute a; + a.type = StunTypes::SOFTWARE; + a.value = StunTypes::createSoftware(clientSoftware); + list += a; + } + + { + StunMessage::Attribute a; + a.type = StunTypes::LIFETIME; + a.value = StunTypes::createLifetime(3600); + list += a; + } + + { + StunMessage::Attribute a; + a.type = StunTypes::REQUESTED_TRANSPORT; + a.value = StunTypes::createRequestedTransport(17); // 17=UDP + list += a; + } + + if(dfState == DF_Unknown) + { + StunMessage::Attribute a; + a.type = StunTypes::DONT_FRAGMENT; + list += a; + } + + message.setAttributes(list); + + trans->setMessage(message); + } + else if(state == Stopping || state == Erroring) + { + StunMessage message; + message.setMethod(StunTypes::Refresh); + message.setId((const quint8 *)transactionId.data()); + + QList<StunMessage::Attribute> list; + + { + StunMessage::Attribute a; + a.type = StunTypes::LIFETIME; + a.value = StunTypes::createLifetime(0); + list += a; + } + + message.setAttributes(list); + + trans->setMessage(message); + } + else if(state == Refreshing) + { + StunMessage message; + message.setMethod(StunTypes::Refresh); + message.setId((const quint8 *)transactionId.data()); + + QList<StunMessage::Attribute> list; + + { + StunMessage::Attribute a; + a.type = StunTypes::LIFETIME; + a.value = StunTypes::createLifetime(3600); + list += a; + } + + message.setAttributes(list); + + trans->setMessage(message); + } + } + + void trans_finished(const XMPP::StunMessage &response) + { + delete trans; + trans = 0; + + bool error = false; + int code; + QString reason; + if(response.mclass() == StunMessage::ErrorResponse) + { + if(!StunTypes::parseErrorCode(response.attribute(StunTypes::ERROR_CODE), &code, &reason)) + { + cleanup(); + errorString = "Unable to parse ERROR-CODE in error response."; + emit q->error(StunAllocate::ErrorProtocol); + return; + } + + error = true; + } + + if(state == Starting) + { + if(error) + { + if(code == StunTypes::UnknownAttribute) + { + QList<quint16> typeList; + if(!StunTypes::parseUnknownAttributes(response.attribute(StunTypes::UNKNOWN_ATTRIBUTES), &typeList)) + { + cleanup(); + errorString = "Unable to parse UNKNOWN-ATTRIBUTES in 420 (Unknown Attribute) error response."; + emit q->error(StunAllocate::ErrorProtocol); + return; + } + + if(typeList.contains(StunTypes::DONT_FRAGMENT)) + { + dfState = DF_Unsupported; + + // stay in same state, try again + doTransaction(); + } + else + { + cleanup(); + errorString = reason; + emit q->error(StunAllocate::ErrorGeneric); + } + + return; + } + else if(code == StunTypes::AllocationMismatch) + { + cleanup(); + errorString = "437 (Allocation Mismatch)."; + emit q->error(StunAllocate::ErrorMismatch); + return; + } + else if(code == StunTypes::InsufficientCapacity) + { + cleanup(); + errorString = reason; + emit q->error(StunAllocate::ErrorCapacity); + return; + } + else if(code == StunTypes::Unauthorized) + { + cleanup(); + errorString = "Unauthorized"; + emit q->error(StunAllocate::ErrorAuth); + return; + } + else + { + cleanup(); + errorString = reason; + emit q->error(StunAllocate::ErrorGeneric); + return; + } + } + + quint32 lifetime; + if(!StunTypes::parseLifetime(response.attribute(StunTypes::LIFETIME), &lifetime)) + { + cleanup(); + errorString = "Unable to parse LIFETIME."; + emit q->error(StunAllocate::ErrorProtocol); + return; + } + + QHostAddress raddr; + quint16 rport; + if(!StunTypes::parseXorRelayedAddress(response.attribute(StunTypes::XOR_RELAYED_ADDRESS), response.magic(), response.id(), &raddr, &rport)) + { + cleanup(); + errorString = "Unable to parse XOR-RELAYED-ADDRESS."; + emit q->error(StunAllocate::ErrorProtocol); + return; + } + + QHostAddress saddr; + quint16 sport; + if(!StunTypes::parseXorMappedAddress(response.attribute(StunTypes::XOR_MAPPED_ADDRESS), response.magic(), response.id(), &saddr, &sport)) + { + cleanup(); + errorString = "Unable to parse XOR-MAPPED-ADDRESS."; + emit q->error(StunAllocate::ErrorProtocol); + return; + } + + if(lifetime < 120) + { + state = Started; // stopWithError requires this + stopWithError(StunAllocate::ErrorProtocol, + "LIFETIME is less than two minutes. That is ridiculous."); + return; + } + + QString str; + if(StunTypes::parseSoftware(response.attribute(StunTypes::SOFTWARE), &str)) + { + serverSoftware = str; + } + + allocateLifetime = lifetime; + relayedAddress = raddr; + relayedPort = rport; + reflexiveAddress = saddr; + reflexivePort = sport; + + if(dfState == DF_Unknown) + dfState = DF_Supported; + + state = Started; + restartRefreshTimer(); + + emit q->started(); + } + else if(state == Stopping || state == Erroring) + { + if(error) + { + // AllocationMismatch on session cancel doesn't count as an error + if(code != StunTypes::AllocationMismatch) + { + cleanup(); + errorString = reason; + emit q->error(StunAllocate::ErrorGeneric); + return; + } + } + + if(state == Stopping) + { + // cleanup will set the state to Stopped + cleanup(); + emit q->stopped(); + } + else // Erroring + { + int code = erroringCode; + QString str = erroringString; + + // cleanup will set the state to Stopped + cleanup(); + errorString = str; + emit q->error((StunAllocate::Error)code); + } + } + else if(state == Refreshing) + { + if(error) + { + cleanup(); + errorString = reason; + emit q->error(StunAllocate::ErrorRejected); + return; + } + + quint32 lifetime; + if(!StunTypes::parseLifetime(response.attribute(StunTypes::LIFETIME), &lifetime)) + { + cleanup(); + errorString = "Unable to parse LIFETIME."; + emit q->error(StunAllocate::ErrorProtocol); + return; + } + + allocateLifetime = lifetime; + + state = Started; + restartRefreshTimer(); + } + } + + void perm_ready() + { + if(updatePermsOut()) + emit q->permissionsChanged(); + } + + void perm_error(XMPP::StunAllocatePermission::Error e, const QString &reason) + { + if(e == StunAllocatePermission::ErrorCapacity) + { + // if we aren't allowed to make anymore permissions, + // don't consider this an error. the perm stays + // in the list inactive. we'll try it again if + // any perms get removed. + return; + } + else if(e == StunAllocatePermission::ErrorForbidden) + { + // silently discard the permission request + StunAllocatePermission *perm = (StunAllocatePermission *)sender(); + QHostAddress addr = perm->addr; + delete perm; + perms.removeAll(perm); + emit q->debugLine(QString("Warning: permission forbidden to %1").arg(addr.toString())); + return; + } + + cleanup(); + errorString = reason; + emit q->error(StunAllocatePermission::errorToStunAllocateError(e)); + } + + void channel_ready() + { + if(updateChannelsOut()) + emit q->channelsChanged(); + } + + void channel_error(XMPP::StunAllocateChannel::Error e, const QString &reason) + { + if(e == StunAllocateChannel::ErrorCapacity) + { + // if we aren't allowed to make anymore channels, + // don't consider this an error. the channel stays + // in the list inactive. we'll try it again if + // any channels get removed. + return; + } + + cleanup(); + errorString = reason; + emit q->error(StunAllocateChannel::errorToStunAllocateError(e)); + } + + void trans_error(XMPP::StunTransaction::Error e) + { + delete trans; + trans = 0; + + cleanup(); + + if(e == StunTransaction::ErrorTimeout) + { + errorString = "Request timed out."; + emit q->error(StunAllocate::ErrorTimeout); + } + else + { + errorString = "Generic transaction error."; + emit q->error(StunAllocate::ErrorGeneric); + } + } +}; + +StunAllocate::StunAllocate(StunTransactionPool *pool) : + QObject(pool) +{ + d = new Private(this); + d->pool = pool; +} + +StunAllocate::~StunAllocate() +{ + delete d; +} + +void StunAllocate::setClientSoftwareNameAndVersion(const QString &str) +{ + d->clientSoftware = str; +} + +void StunAllocate::start() +{ + d->start(); +} + +void StunAllocate::start(const QHostAddress &addr, int port) +{ + d->start(addr, port); +} + +void StunAllocate::stop() +{ + d->stop(); +} + +QString StunAllocate::serverSoftwareNameAndVersion() const +{ + return d->serverSoftware; +} + +QHostAddress StunAllocate::reflexiveAddress() const +{ + return d->reflexiveAddress; +} + +int StunAllocate::reflexivePort() const +{ + return d->reflexivePort; +} + +QHostAddress StunAllocate::relayedAddress() const +{ + return d->relayedAddress; +} + +int StunAllocate::relayedPort() const +{ + return d->relayedPort; +} + +QList<QHostAddress> StunAllocate::permissions() const +{ + return d->permsOut; +} + +void StunAllocate::setPermissions(const QList<QHostAddress> &perms) +{ + d->setPermissions(perms); +} + +QList<StunAllocate::Channel> StunAllocate::channels() const +{ + return d->channelsOut; +} + +void StunAllocate::setChannels(const QList<Channel> &channels) +{ + d->setChannels(channels); +} + +int StunAllocate::packetHeaderOverhead(const QHostAddress &addr, int port) const +{ + int channelId = d->getChannel(addr, port); + + if(channelId != -1) + { + // overhead of ChannelData + if(d->pool->mode() == StunTransaction::Udp) + return 4; + else // Tcp + return 4 + 3; // add 3 for potential padding + } + else + { + // we add 3 for potential padding + if(d->dfState == StunAllocate::Private::DF_Supported) + { + // overhead of STUN-based data, with DONT_FRAGMENT + return 40 + 3; + } + else + { + // overhead of STUN-based data, without DONT-FRAGMENT + return 36 + 3; + } + } + + return -1; +} + +QByteArray StunAllocate::encode(const QByteArray &datagram, const QHostAddress &addr, int port) +{ + int channelId = d->getChannel(addr, port); + + if(channelId != -1) + { + if(datagram.size() > 65535) + return QByteArray(); + + quint16 num = channelId; + quint16 len = datagram.size(); + + int plen = len; + + // in tcp mode, round to up to nearest 4 bytes + if(d->pool->mode() == StunTransaction::Tcp) + { + int remainder = plen % 4; + if(remainder != 0) + plen += (4 - remainder); + } + + QByteArray out(4 + plen, 0); + StunUtil::write16((quint8 *)out.data(), num); + StunUtil::write16((quint8 *)out.data() + 2, len); + memcpy(out.data() + 4, datagram.data(), datagram.size()); + + return out; + } + else + { + StunMessage message; + message.setClass(StunMessage::Indication); + message.setMethod(StunTypes::Send); + QByteArray id = d->pool->generateId(); + message.setId((const quint8 *)id.data()); + + QList<StunMessage::Attribute> list; + + { + StunMessage::Attribute a; + a.type = StunTypes::XOR_PEER_ADDRESS; + a.value = StunTypes::createXorPeerAddress(addr, port, message.magic(), message.id()); + list += a; + } + + if(d->dfState == StunAllocate::Private::DF_Supported) + { + StunMessage::Attribute a; + a.type = StunTypes::DONT_FRAGMENT; + list += a; + } + + { + StunMessage::Attribute a; + a.type = StunTypes::DATA; + a.value = datagram; + list += a; + } + + message.setAttributes(list); + + return message.toBinary(); + } +} + +QByteArray StunAllocate::decode(const QByteArray &encoded, QHostAddress *addr, int *port) +{ + if(encoded.size() < 4) + return QByteArray(); + + quint16 num = StunUtil::read16((const quint8 *)encoded.data()); + quint16 len = StunUtil::read16((const quint8 *)encoded.data() + 2); + if(encoded.size() - 4 < (int)len) + return QByteArray(); + + if(!d->getAddressPort(num, addr, port)) + return QByteArray(); + + return encoded.mid(4, len); +} + +QByteArray StunAllocate::decode(const StunMessage &encoded, QHostAddress *addr, int *port) +{ + QHostAddress paddr; + quint16 pport; + + if(!StunTypes::parseXorPeerAddress(encoded.attribute(StunTypes::XOR_PEER_ADDRESS), encoded.magic(), encoded.id(), &paddr, &pport)) + return QByteArray(); + + QByteArray data = encoded.attribute(StunTypes::DATA); + if(data.isNull()) + return QByteArray(); + + *addr = paddr; + *port = pport; + return data; +} + +QString StunAllocate::errorString() const +{ + return d->errorString; +} + +bool StunAllocate::containsChannelData(const quint8 *data, int size) +{ + return (check_channelData(data, size) != -1 ? true : false); +} + +QByteArray StunAllocate::readChannelData(const quint8 *data, int size) +{ + int len = check_channelData(data, size); + if(len != -1) + return QByteArray((const char *)data, len); + else + return QByteArray(); +} + +} + +#include "stunallocate.moc"
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stunallocate.h
Added
@@ -0,0 +1,135 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef STUNALLOCATE_H +#define STUNALLOCATE_H + +#include <QObject> +#include <QList> +#include <QHostAddress> + +class QByteArray; + +namespace XMPP { + +class StunMessage; +class StunTransactionPool; + +class StunAllocate : public QObject +{ + Q_OBJECT + +public: + enum Error + { + ErrorGeneric, + ErrorTimeout, + ErrorAuth, + ErrorRejected, + ErrorProtocol, + ErrorCapacity, + ErrorMismatch + }; + + class Channel + { + public: + QHostAddress address; + int port; + + Channel(const QHostAddress &_address, int _port) : + address(_address), + port(_port) + { + } + + inline bool operator==(const Channel &other) + { + if(address == other.address && port == other.port) + return true; + else + return false; + } + + inline bool operator!=(const Channel &other) + { + return !operator==(other); + } + }; + + StunAllocate(StunTransactionPool *pool); + ~StunAllocate(); + + void setClientSoftwareNameAndVersion(const QString &str); + + void start(); + void start(const QHostAddress &addr, int port); // use addr association + void stop(); + + QString serverSoftwareNameAndVersion() const; + + QHostAddress reflexiveAddress() const; + int reflexivePort() const; + + QHostAddress relayedAddress() const; + int relayedPort() const; + + QList<QHostAddress> permissions() const; + void setPermissions(const QList<QHostAddress> &perms); + + QList<Channel> channels() const; + void setChannels(const QList<Channel> &channels); + + int packetHeaderOverhead(const QHostAddress &addr, int port) const; + + QByteArray encode(const QByteArray &datagram, const QHostAddress &addr, int port); + QByteArray decode(const QByteArray &encoded, QHostAddress *addr = 0, int *port = 0); + QByteArray decode(const StunMessage &encoded, QHostAddress *addr = 0, int *port = 0); + + QString errorString() const; + + static bool containsChannelData(const quint8 *data, int size); + static QByteArray readChannelData(const quint8 *data, int size); + +signals: + void started(); + void stopped(); + void error(XMPP::StunAllocate::Error e); + + // emitted after calling setPermissions() + void permissionsChanged(); + + // emitted after calling setChannels() + void channelsChanged(); + + // not DOR-SS/DS safe + void debugLine(const QString &line); + +private: + Q_DISABLE_COPY(StunAllocate) + + class Private; + friend class Private; + Private *d; +}; + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stunbinding.cpp
Added
@@ -0,0 +1,300 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "stunbinding.h" + +#include <QHostAddress> +#include "stunmessage.h" +#include "stuntypes.h" +#include "stuntransaction.h" + +namespace XMPP { + +class StunBinding::Private : public QObject +{ + Q_OBJECT + +public: + StunBinding *q; + StunTransactionPool *pool; + StunTransaction *trans; + QHostAddress stunAddr; + int stunPort; + QHostAddress addr; + int port; + QString errorString; + bool use_extPriority, use_extIceControlling, use_extIceControlled; + quint32 extPriority; + bool extUseCandidate; + quint64 extIceControlling, extIceControlled; + QString stuser, stpass; + bool fpRequired; + + Private(StunBinding *_q) : + QObject(_q), + q(_q), + pool(0), + trans(0), + use_extPriority(false), + use_extIceControlling(false), + use_extIceControlled(false), + extUseCandidate(false), + fpRequired(false) + { + } + + ~Private() + { + delete trans; + } + + void start(const QHostAddress &_addr = QHostAddress(), int _port = -1) + { + Q_ASSERT(!trans); + + stunAddr = _addr; + stunPort = _port; + + trans = new StunTransaction(this); + connect(trans, SIGNAL(createMessage(const QByteArray &)), SLOT(trans_createMessage(const QByteArray &))); + connect(trans, SIGNAL(finished(const XMPP::StunMessage &)), SLOT(trans_finished(const XMPP::StunMessage &))); + connect(trans, SIGNAL(error(XMPP::StunTransaction::Error)), SLOT(trans_error(XMPP::StunTransaction::Error))); + + if(!stuser.isEmpty()) + { + trans->setShortTermUsername(stuser); + trans->setShortTermPassword(stpass); + } + + trans->setFingerprintRequired(fpRequired); + + trans->start(pool, stunAddr, stunPort); + } + +private slots: + void trans_createMessage(const QByteArray &transactionId) + { + StunMessage message; + message.setMethod(StunTypes::Binding); + message.setId((const quint8 *)transactionId.data()); + + QList<StunMessage::Attribute> list; + + if(use_extPriority) + { + StunMessage::Attribute a; + a.type = StunTypes::PRIORITY; + a.value = StunTypes::createPriority(extPriority); + list += a; + } + + if(extUseCandidate) + { + StunMessage::Attribute a; + a.type = StunTypes::USE_CANDIDATE; + list += a; + } + + if(use_extIceControlling) + { + StunMessage::Attribute a; + a.type = StunTypes::ICE_CONTROLLING; + a.value = StunTypes::createIceControlling(extIceControlling); + list += a; + } + + if(use_extIceControlled) + { + StunMessage::Attribute a; + a.type = StunTypes::ICE_CONTROLLED; + a.value = StunTypes::createIceControlled(extIceControlled); + list += a; + } + + message.setAttributes(list); + + trans->setMessage(message); + } + + void trans_finished(const XMPP::StunMessage &response) + { + delete trans; + trans = 0; + + bool error = false; + int code; + QString reason; + if(response.mclass() == StunMessage::ErrorResponse) + { + if(!StunTypes::parseErrorCode(response.attribute(StunTypes::ERROR_CODE), &code, &reason)) + { + errorString = "Unable to parse ERROR-CODE in error response."; + emit q->error(StunBinding::ErrorProtocol); + return; + } + + error = true; + } + + if(error) + { + errorString = reason; + if(code == StunTypes::RoleConflict) + emit q->error(StunBinding::ErrorConflict); + else + emit q->error(StunBinding::ErrorRejected); + return; + } + + QHostAddress saddr; + quint16 sport = 0; + + QByteArray val; + val = response.attribute(StunTypes::XOR_MAPPED_ADDRESS); + if(!val.isNull()) + { + if(!StunTypes::parseXorMappedAddress(val, response.magic(), response.id(), &saddr, &sport)) + { + errorString = "Unable to parse XOR-MAPPED-ADDRESS response."; + emit q->error(StunBinding::ErrorProtocol); + return; + } + } + else + { + val = response.attribute(StunTypes::MAPPED_ADDRESS); + if(!val.isNull()) + { + if(!StunTypes::parseMappedAddress(val, &saddr, &sport)) + { + errorString = "Unable to parse MAPPED-ADDRESS response."; + emit q->error(StunBinding::ErrorProtocol); + return; + } + } + else + { + errorString = "Response does not contain XOR-MAPPED-ADDRESS or MAPPED-ADDRESS."; + emit q->error(StunBinding::ErrorProtocol); + return; + } + } + + addr = saddr; + port = sport; + emit q->success(); + } + + void trans_error(XMPP::StunTransaction::Error e) + { + delete trans; + trans = 0; + + if(e == StunTransaction::ErrorTimeout) + { + errorString = "Request timed out."; + emit q->error(StunBinding::ErrorTimeout); + } + else + { + errorString = "Generic transaction error."; + emit q->error(StunBinding::ErrorGeneric); + } + } +}; + +StunBinding::StunBinding(StunTransactionPool *pool) : + QObject(pool) +{ + d = new Private(this); + d->pool = pool; +} + +StunBinding::~StunBinding() +{ + delete d; +} + +void StunBinding::setPriority(quint32 i) +{ + d->use_extPriority = true; + d->extPriority = i; +} + +void StunBinding::setUseCandidate(bool enabled) +{ + d->extUseCandidate = enabled; +} + +void StunBinding::setIceControlling(quint64 i) +{ + d->use_extIceControlling = true; + d->extIceControlling = i; +} + +void StunBinding::setIceControlled(quint64 i) +{ + d->use_extIceControlled = true; + d->extIceControlled = i; +} + +void StunBinding::setShortTermUsername(const QString &username) +{ + d->stuser = username; +} + +void StunBinding::setShortTermPassword(const QString &password) +{ + d->stpass = password; +} + +void StunBinding::setFingerprintRequired(bool enabled) +{ + d->fpRequired = enabled; +} + +void StunBinding::start() +{ + d->start(); +} + +void StunBinding::start(const QHostAddress &addr, int port) +{ + d->start(addr, port); +} + +QHostAddress StunBinding::reflexiveAddress() const +{ + return d->addr; +} + +int StunBinding::reflexivePort() const +{ + return d->port; +} + +QString StunBinding::errorString() const +{ + return d->errorString; +} + +} + +#include "stunbinding.moc"
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stunbinding.h
Added
@@ -0,0 +1,83 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef STUNBINDING_H +#define STUNBINDING_H + +#include <QObject> + +class QHostAddress; + +namespace XMPP { + +class StunTransactionPool; + +class StunBinding : public QObject +{ + Q_OBJECT + +public: + enum Error + { + ErrorGeneric, + ErrorTimeout, + ErrorRejected, + ErrorProtocol, + ErrorConflict + }; + + StunBinding(StunTransactionPool *pool); + ~StunBinding(); + + // for ICE-use only + void setPriority(quint32 i); + void setUseCandidate(bool enabled); + void setIceControlling(quint64 i); + void setIceControlled(quint64 i); + + void setShortTermUsername(const QString &username); + void setShortTermPassword(const QString &password); + + void setFingerprintRequired(bool enabled); + + void start(); + void start(const QHostAddress &addr, int port); // use addr association + + QHostAddress reflexiveAddress() const; + int reflexivePort() const; + + // non-translatable diagnostic string for convenience + QString errorString() const; + +signals: + void success(); + void error(XMPP::StunBinding::Error e); + +private: + Q_DISABLE_COPY(StunBinding) + + class Private; + friend class Private; + Private *d; +}; + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stunmessage.cpp
Added
@@ -0,0 +1,733 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "stunmessage.h" + +#include <QSharedData> +#include <QtCrypto> +#include "stunutil.h" + +#define ENSURE_D { if(!d) d = new Private; } + +namespace XMPP { + +using namespace StunUtil; + +// some attribute types we need to explicitly support +enum +{ + AttribMessageIntegrity = 0x0008, + AttribFingerprint = 0x8028 +}; + +// adapted from public domain source by Ross Williams and Eric Durbin +unsigned long crctable256 = +{ + 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, + 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, + 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, + 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, + 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, + 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, + 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, + 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, + 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, + 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, + 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, + 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, + 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, + 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, + 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, + 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, + 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, + 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, + 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, + 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, + 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, + 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, + 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, + 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, + 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, + 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, + 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, + 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, + 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, + 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, + 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, + 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, + 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, + 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, + 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, + 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, + 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, + 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, + 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, + 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, + 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, + 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, + 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, + 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, + 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, + 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, + 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, + 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, + 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, + 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, + 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, + 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, + 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, + 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, + 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, + 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, + 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, + 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, + 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, + 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, + 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, + 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, + 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, + 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL +}; + +class Crc32 +{ +private: + quint32 result; + +public: + Crc32() + { + clear(); + } + + void clear() + { + result = 0xffffffff; + } + + void update(const QByteArray &in) + { + for(int n = 0; n < in.size(); ++n) + result = (result >> 8) ^ (crctable(result & 0xff) ^ (quint8)inn); + } + + quint32 final() + { + return result ^= 0xffffffff; + } + + static quint32 process(const QByteArray &in) + { + Crc32 c; + c.update(in); + return c.final(); + } +}; + +static quint8 magic_cookie4 = { 0x21, 0x12, 0xA4, 0x42 }; + +// do 3-field check of stun packet +// returns length of packet not counting the header, or -1 on error +static int check_and_get_length(const QByteArray &buf) +{ + // stun packets are at least 20 bytes + if(buf.size() < 20) + return -1; + + // minimal 3-field check + + // top 2 bits of packet must be 0 + if(buf0 & 0xC0) + return -1; + + const quint8 *p = (const quint8 *)buf.data(); + quint16 mlen = read16(p + 2); + + // bottom 2 bits of message length field must be 0 + if(mlen & 0x03) + return -1; + + // (also, the message length should be a reasonable size) + if(mlen + 20 > buf.size()) + return -1; + + // magic cookie must be set + if(memcmp(p + 4, magic_cookie, 4) != 0) + return -1; + + return mlen; +} + +#define ATTRIBUTE_AREA_START 20 +#define ATTRIBUTE_AREA_MAX 65535 +#define ATTRIBUTE_VALUE_MAX 65531 + +// note: because the attribute area of the packet has a maximum size of +// 2^16-1, and each attribute itself has a 4 byte header, it follows that +// the maximum size of an attribute's value is 2^16-5. this means that, +// even if padded with up to 3 bytes, the physical size of an attribute's +// value will not overflow a 16-bit unsigned integer. +static quint16 round_up_length(quint16 in) +{ + Q_ASSERT(in <= ATTRIBUTE_VALUE_MAX); + quint16 out = in; + quint16 remainder = out % 4; + if(remainder != 0) + out += (4 - remainder); + return out; +} + +// buf = entire stun packet +// offset = byte index of current attribute (first is offset=20) +// type = take attribute type +// len = take attribute value length (value is at offset + 4) +// returns offset of next attribute, -1 if no more +static int get_attribute_props(const QByteArray &buf, int offset, quint16 *type, int *len) +{ + Q_ASSERT(offset >= ATTRIBUTE_AREA_START); + + const quint8 *p = (const quint8 *)buf.data(); + + // need at least 4 bytes for an attribute + if(offset + 4 > buf.size()) + return -1; + + quint16 _type = read16(p + offset); + offset += 2; + quint16 _alen = read16(p + offset); + offset += 2; + + // get physical length. stun attributes are 4-byte aligned, and may + // contain 0-3 bytes of padding. + quint16 plen = round_up_length(_alen); + if(offset + plen > buf.size()) + return -1; + + *type = _type; + *len = _alen; + return offset + plen; +} + +// buf = entire stun packet +// type = attribute type to find +// len = take attribute value length (value is at offset + 4) +// next = take offset of next attribute +// returns offset of found attribute, -1 if not found +static int find_attribute(const QByteArray &buf, quint16 type, int *len, int *next = 0) +{ + int at = ATTRIBUTE_AREA_START; + quint16 _type; + int _len; + int _next; + + while(1) + { + _next = get_attribute_props(buf, at, &_type, &_len); + if(_next == -1) + break; + if(_type == type) + { + *len = _len; + if(next) + *next = _next; + return at; + } + at = _next; + } + + return -1; +} + +// buf = stun packet to append attribute to +// type = type of attribute +// len = length of value +// returns offset of new attribute, or -1 if it can't fit +// note: attribute value is located at offset + 4 and is uninitialized +// note: padding following attribute is zeroed out +static int append_attribute_uninitialized(QByteArray *buf, quint16 type, int len) +{ + if(len > ATTRIBUTE_VALUE_MAX) + return -1; + + quint16 alen = (quint16)len; + quint16 plen = round_up_length(alen); + + if((buf->size() - ATTRIBUTE_AREA_START) + 4 + plen > ATTRIBUTE_AREA_MAX) + return -1; + + int at = buf->size(); + buf->resize(buf->size() + 4 + plen); + quint8 *p = (quint8 *)buf->data(); + + write16(p + at, type); + write16(p + at + 2, alen); + + // padding + for(int n = 0; n < plen - alen; ++n) + pat + alen + n = 0; + + return at; +} + +static quint32 fingerprint_calc(const quint8 *buf, int size) +{ + QByteArray region = QByteArray::fromRawData((const char *)buf, size); + return Crc32::process(region) ^ 0x5354554e; +} + +static QByteArray message_integrity_calc(const quint8 *buf, int size, const QByteArray &key) +{ + QCA::MessageAuthenticationCode hmac("hmac(sha1)", key); + QByteArray region = QByteArray::fromRawData((const char *)buf, size); + QByteArray result = hmac.process(region).toByteArray(); + Q_ASSERT(result.size() == 20); + return result; +} + +// look for fingerprint attribute and confirm it +// buf = entire stun packet +// returns true if fingerprint attribute exists and is correct +static bool fingerprint_check(const QByteArray &buf) +{ + int at, len; + at = find_attribute(buf, AttribFingerprint, &len); + if(at == -1 || len != 4) // value must be 4 bytes + return false; + + const quint8 *p = (const quint8 *)buf.data(); + quint32 fpval = read32(p + at + 4); + quint32 fpcalc = fingerprint_calc(p, at); + if(fpval == fpcalc) + return true; + else + return false; +} + +// copy the input buffer and prepare for message integrity checking. the +// packet is truncated after the message-integrity attribute (since nothing +// after it is protected), and the packet length is adjusted in the header +// accordingly. +// buf = input stun packet +// out = take output stun packet +// offset = take offset of message-integrity attribute +// returns true if message-integrity attribute exists and packet is prepared +// note: message-integrity value is at offset + 4 and is exactly 20 bytes +static bool message_integrity_prep(const QByteArray &buf, QByteArray *out, int *offset) +{ + int at, len, next; + at = find_attribute(buf, AttribMessageIntegrity, &len, &next); + if(at == -1 || len != 20) // value must be 20 bytes + return false; + + // prepare new attribute area size + int i = next - ATTRIBUTE_AREA_START; + + // new value must be divisible by 4 + if(i % 4 != 0) + return false; + + // copy truncated packet + *out = buf.mid(0, next); + + // set new length in header + quint16 newlen = (quint16)i; + write16((quint8 *)out->data() + 2, newlen); + + *offset = at; + return true; +} + +// confirm message integrity +// buf = prepared stun packet (from message_integrity_prep()) +// offset = offset of message-integrity attribute +// key = the HMAC key +// returns true if correct +static bool message_integrity_check(const QByteArray &buf, int offset, const QByteArray &key) +{ + QByteArray mival = QByteArray::fromRawData(buf.data() + offset + 4, 20); + QByteArray micalc = message_integrity_calc((const quint8 *)buf.data(), offset, key); + if(mival == micalc) + return true; + else + return false; +} + +class StunMessage::Private : public QSharedData +{ +public: + StunMessage::Class mclass; + quint16 method; + quint8 magic4; + quint8 id12; + QList<Attribute> attribs; + + Private() + { + mclass = (StunMessage::Class)-1; + method = 0; + memcpy(magic, magic_cookie, 4); + memset(id, 0, 12); + } +}; + +StunMessage::StunMessage() : + d(0) +{ +} + +StunMessage::StunMessage(const StunMessage &from) : + d(from.d) +{ +} + +StunMessage::~StunMessage() +{ +} + +StunMessage & StunMessage::operator=(const StunMessage &from) +{ + d = from.d; + return *this; +} + +bool StunMessage::isNull() const +{ + return (d ? false : true); +} + +StunMessage::Class StunMessage::mclass() const +{ + Q_ASSERT(d); + return d->mclass; +} + +quint16 StunMessage::method() const +{ + Q_ASSERT(d); + return d->method; +} + +const quint8 *StunMessage::magic() const +{ + Q_ASSERT(d); + return d->magic; +} + +const quint8 *StunMessage::id() const +{ + Q_ASSERT(d); + return d->id; +} + +QList<StunMessage::Attribute> StunMessage::attributes() const +{ + Q_ASSERT(d); + return d->attribs; +} + +QByteArray StunMessage::attribute(quint16 type) const +{ + Q_ASSERT(d); + + foreach(const Attribute &i, d->attribs) + { + if(i.type == type) + return i.value; + } + return QByteArray(); +} + +void StunMessage::setClass(Class mclass) +{ + ENSURE_D + d->mclass = mclass; +} + +void StunMessage::setMethod(quint16 method) +{ + ENSURE_D + d->method = method; +} + +void StunMessage::setMagic(const quint8 *magic) +{ + ENSURE_D + memcpy(d->magic, magic, 4); +} + +void StunMessage::setId(const quint8 *id) +{ + ENSURE_D + memcpy(d->id, id, 12); +} + +void StunMessage::setAttributes(const QList<Attribute> &attribs) +{ + ENSURE_D + d->attribs = attribs; +} + +QByteArray StunMessage::toBinary(int validationFlags, const QByteArray &key) const +{ + Q_ASSERT(d); + + // header + QByteArray buf(20, 0); + quint8 *p = (quint8 *)buf.data(); + + quint8 classbits = 0; + if(d->mclass == Request) + classbits = 0; // 00 + else if(d->mclass == Indication) + classbits = 1; // 01 + else if(d->mclass == SuccessResponse) + classbits = 2; // 10 + else if(d->mclass == ErrorResponse) + classbits = 3; // 11 + else + Q_ASSERT(0); + + // method bits are split into 3 sections + quint16 m1, m2, m3; + m1 = d->method & 0x0f80; // M7-11 + m1 <<= 2; + m2 = d->method & 0x0070; // M4-6 + m2 <<= 1; + m3 = d->method & 0x000f; // M0-3 + + // class bits are split into 2 sections + quint16 c1, c2; + c1 = classbits & 0x02; // C1 + c1 <<= 7; + c2 = classbits & 0x01; // C0 + c2 <<= 4; + + quint16 type = m1 | m2 | m3 | c1 | c2; + write16(p, type); + write16(p + 2, 0); + memcpy(p + 4, d->magic, 4); + memcpy(p + 8, d->id, 12); + + foreach(const Attribute &i, d->attribs) + { + int at = append_attribute_uninitialized(&buf, i.type, i.value.size()); + if(at == -1) + return QByteArray(); + + p = (quint8 *)buf.data(); // follow the resize + + memcpy(buf.data() + at + 4, i.value.data(), i.value.size()); + } + + // set attribute area size + write16(p + 2, buf.size() - ATTRIBUTE_AREA_START); + + if(validationFlags & MessageIntegrity) + { + quint16 alen = 20; // size of hmac(sha1) + int at = append_attribute_uninitialized(&buf, AttribMessageIntegrity, alen); + if(at == -1) + return QByteArray(); + + p = (quint8 *)buf.data(); // follow the resize + + // set attribute area size to include the new attribute + write16(p + 2, buf.size() - ATTRIBUTE_AREA_START); + + // now calculate the hash and fill in the value + QByteArray result = message_integrity_calc(p, at, key); + Q_ASSERT(result.size() == alen); + memcpy(p + at + 4, result.data(), alen); + } + + if(validationFlags & Fingerprint) + { + quint16 alen = 4; // size of crc32 + int at = append_attribute_uninitialized(&buf, AttribFingerprint, alen); + if(at == -1) + return QByteArray(); + + p = (quint8 *)buf.data(); // follow the resize + + // set attribute area size to include the new attribute + write16(p + 2, buf.size() - ATTRIBUTE_AREA_START); + + // now calculate the fingerprint and fill in the value + quint32 fpcalc = fingerprint_calc(p, at); + write32(p + at + 4, fpcalc); + } + + return buf; +} + +StunMessage StunMessage::fromBinary(const QByteArray &a, ConvertResult *result, int validationFlags, const QByteArray &key) +{ + int mlen = check_and_get_length(a); + if(mlen == -1) + { + if(result) + *result = ErrorFormat; + return StunMessage(); + } + + if(validationFlags & Fingerprint) + { + if(!fingerprint_check(a)) + { + if(result) + *result = ErrorFingerprint; + return StunMessage(); + } + } + + QByteArray in; + + if(validationFlags & MessageIntegrity) + { + int offset; + if(!message_integrity_prep(a, &in, &offset)) + { + if(result) + *result = ErrorMessageIntegrity; + return StunMessage(); + } + + if(!message_integrity_check(in, offset, key)) + { + if(result) + *result = ErrorMessageIntegrity; + return StunMessage(); + } + } + else + in = a; + + // all validating complete, now just parse the packet + + const quint8 *p = (const quint8 *)in.data(); + + // method bits are split into 3 sections + quint16 m1, m2, m3; + m1 = p0 & 0x3e; // M7-11 + m1 <<= 6; + m2 = p1 & 0xe0; // M4-6 + m2 >>= 1; + m3 = p1 & 0x0f; // M0-3 + + // class bits are split into 2 sections + quint8 c1, c2; + c1 = p0 & 0x01; // C1 + c1 <<= 1; + c2 = p1 & 0x10; // C0 + c2 >>= 4; + + quint16 method = m1 | m2 | m3; + quint8 classbits = c1 | c2; + + Class mclass; + if(classbits == 0) // 00 + mclass = Request; + else if(classbits == 1) // 01 + mclass = Indication; + else if(classbits == 2) // 10 + mclass = SuccessResponse; + else // 11 + mclass = ErrorResponse; + + StunMessage out; + out.setClass(mclass); + out.setMethod(method); + out.setMagic(p + 4); + out.setId(p + 8); + + QList<Attribute> list; + int at = ATTRIBUTE_AREA_START; + while(1) + { + quint16 type; + int len; + int next; + + next = get_attribute_props(in, at, &type, &len); + if(next == -1) + break; + + Attribute attrib; + attrib.type = type; + attrib.value = in.mid(at + 4, len); + list += attrib; + + at = next; + } + out.setAttributes(list); + + if(result) + *result = ConvertGood; + return out; +} + +bool StunMessage::isProbablyStun(const QByteArray &a) +{ + return (check_and_get_length(a) != -1 ? true : false); +} + +StunMessage::Class StunMessage::extractClass(const QByteArray &in) +{ + const quint8 *p = (const quint8 *)in.data(); + + // class bits are split into 2 sections + quint8 c1, c2; + c1 = p0 & 0x01; // C1 + c1 <<= 1; + c2 = p1 & 0x10; // C0 + c2 >>= 4; + + quint8 classbits = c1 | c2; + + Class mclass; + if(classbits == 0) // 00 + mclass = Request; + else if(classbits == 1) // 01 + mclass = Indication; + else if(classbits == 2) // 10 + mclass = SuccessResponse; + else // 11 + mclass = ErrorResponse; + + return mclass; +} + +bool StunMessage::containsStun(const quint8 *data, int size) +{ + // check_and_get_length does a full packet check so it works even on a stream + return (check_and_get_length(QByteArray::fromRawData((const char *)data, size)) != -1 ? true : false); +} + +QByteArray StunMessage::readStun(const quint8 *data, int size) +{ + QByteArray in = QByteArray::fromRawData((const char *)data, size); + int mlen = check_and_get_length(in); + if(mlen != -1) + return QByteArray((const char *)data, mlen + 20); + else + return QByteArray(); +} + +}
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stunmessage.h
Added
@@ -0,0 +1,111 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef STUNMESSAGE_H +#define STUNMESSAGE_H + +#include <QByteArray> +#include <QList> +#include <QSharedDataPointer> + +namespace XMPP { + +class StunMessage +{ +public: + enum Class + { + Request, + SuccessResponse, + ErrorResponse, + Indication + }; + + enum ValidationFlags + { + Fingerprint = 0x01, + + // you must have the hmac(sha1) algorithm in QCA to use + MessageIntegrity = 0x02 + }; + + enum ConvertResult + { + ConvertGood, + ErrorFormat, + ErrorFingerprint, + ErrorMessageIntegrity, + ErrorConvertUnknown = 64 + }; + + class Attribute + { + public: + quint16 type; + QByteArray value; + }; + + StunMessage(); + StunMessage(const StunMessage &from); + ~StunMessage(); + StunMessage & operator=(const StunMessage &from); + + bool isNull() const; + Class mclass() const; + quint16 method() const; + const quint8 *magic() const; // 4 bytes + const quint8 *id() const; // 12 bytes + QList<Attribute> attributes() const; + + // returns the first instance or null + QByteArray attribute(quint16 type) const; + + void setClass(Class mclass); + void setMethod(quint16 method); + void setMagic(const quint8 *magic); // 4 bytes + void setId(const quint8 *id); // 12 bytes + void setAttributes(const QList<Attribute> &attribs); + + QByteArray toBinary(int validationFlags = 0, const QByteArray &key = QByteArray()) const; + static StunMessage fromBinary(const QByteArray &a, ConvertResult *result = 0, int validationFlags = 0, const QByteArray &key = QByteArray()); + + // minimal 3-field check + static bool isProbablyStun(const QByteArray &a); + + // extract out the class value from a raw packet. assumes that 'a' has + // already passed isProbablyStun() + static Class extractClass(const QByteArray &a); + + // examine raw data, such as from a stream, to see if it contains a + // stun packet + static bool containsStun(const quint8 *data, int size); + + // try to read a stun packet from the raw data, else return null. + // a successful result can be passed to fromBinary() + static QByteArray readStun(const quint8 *data, int size); + +private: + class Private; + QSharedDataPointer<Private> d; +}; + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stuntransaction.cpp
Added
@@ -0,0 +1,745 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "stuntransaction.h" + +#include <QHash> +#include <QMetaType> +#include <QTime> +#include <QTimer> +#include <QtCrypto> +#include "stunutil.h" +#include "stunmessage.h" +#include "stuntypes.h" + +Q_DECLARE_METATYPE(XMPP::StunTransaction::Error) + +namespace XMPP { + +// parse a stun message, optionally performing validity checks. the +// StunMessage class itself provides parsing with validity or parsing +// without validity, but it does not provide a way to do both together, +// so we attempt to do that here. +// TODO: consider moving this code into StunMessage +static StunMessage parse_stun_message(const QByteArray &packet, int *validationFlags, const QByteArray &key) +{ + // ideally we shouldn't fully parse the packet more than once. the + // integrity checks performed by fromBinary do not require fully + // parsing the packet, so we should be able to avoid most redundant + // processing. fromBinary checks the fingerprint first, and we + // can use that knowledge to avoid duplicating integrity checks. + int flags = 0; + StunMessage::ConvertResult result; + StunMessage msg = StunMessage::fromBinary(packet, &result, StunMessage::MessageIntegrity | StunMessage::Fingerprint, key); + if(result == StunMessage::ErrorFingerprint) + { + // if fingerprint fails, then it is the only thing that was + // performed and we can skip it now. + msg = StunMessage::fromBinary(packet, &result, StunMessage::MessageIntegrity, key); + if(result == StunMessage::ErrorMessageIntegrity) + { + // if message-integrity fails, then it is the only + // thing that was performed and we can skip it now + msg = StunMessage::fromBinary(packet, &result); + if(result == StunMessage::ConvertGood) + flags = 0; + else + return msg; // null + } + else if(result == StunMessage::ConvertGood) + flags = StunMessage::MessageIntegrity; + else + return msg; // null + } + else if(result == StunMessage::ErrorMessageIntegrity) + { + // fingerprint succeeded, but message-integrity failed. parse + // without validation now (to skip redundant + // fingerprint/message-integrity checks), and assume correct + // fingerprint + msg = StunMessage::fromBinary(packet, &result); + if(result == StunMessage::ConvertGood) + flags = StunMessage::Fingerprint; + else + return msg; // null + } + else if(result == StunMessage::ConvertGood) + flags = StunMessage::MessageIntegrity | StunMessage::Fingerprint; + else + return msg; // null + + *validationFlags = flags; + return msg; +} + +class StunTransactionPoolPrivate : public QObject +{ + Q_OBJECT + +public: + StunTransactionPool *q; + StunTransaction::Mode mode; + QSet<StunTransaction*> transactions; + QHash<StunTransaction*,QByteArray> transToId; + QHash<QByteArray,StunTransaction*> idToTrans; + bool useLongTermAuth; + bool needLongTermAuth; + bool triedLongTermAuth; + QString user; + QCA::SecureArray pass; + QString realm; + QString nonce; + int debugLevel; + + StunTransactionPoolPrivate(StunTransactionPool *_q) : + QObject(_q), + q(_q), + useLongTermAuth(false), + needLongTermAuth(false), + triedLongTermAuth(false), + debugLevel(StunTransactionPool::DL_None) + { + } + + QByteArray generateId() const; + void insert(StunTransaction *trans); + void remove(StunTransaction *trans); + void transmit(StunTransaction *trans); +}; + +//---------------------------------------------------------------------------- +// StunTransaction +//---------------------------------------------------------------------------- +class StunTransactionPrivate : public QObject +{ + Q_OBJECT + +public: + StunTransaction *q; + + StunTransactionPool *pool; + bool active; + StunTransaction::Mode mode; + StunMessage origMessage; + QByteArray id; + QByteArray packet; + QHostAddress to_addr; + int to_port; + + int rto, rc, rm, ti; + int tries; + int last_interval; + QTimer *t; + + QString stuser; + QString stpass; + bool fpRequired; + QByteArray key; + QTime time; + + StunTransactionPrivate(StunTransaction *_q) : + QObject(_q), + q(_q), + pool(0), + fpRequired(false) + { + qRegisterMetaType<StunTransaction::Error>(); + + active = false; + + t = new QTimer(this); + connect(t, SIGNAL(timeout()), SLOT(t_timeout())); + t->setSingleShot(true); + + // defaults from RFC 5389 + rto = 500; + rc = 7; + rm = 16; + ti = 39500; + } + + ~StunTransactionPrivate() + { + if(pool) + pool->d->remove(q); + + t->disconnect(this); + t->setParent(0); + t->deleteLater(); + } + + void start(StunTransactionPool *_pool, const QHostAddress &toAddress, int toPort) + { + pool = _pool; + mode = pool->d->mode; + to_addr = toAddress; + to_port = toPort; + + tryRequest(); + } + + void setMessage(const StunMessage &request) + { + origMessage = request; + } + + void retry() + { + Q_ASSERT(!active); + pool->d->remove(q); + + tryRequest(); + } + + void tryRequest() + { + emit q->createMessage(pool->d->generateId()); + + if(origMessage.isNull()) + { + // since a transaction is not cancelable nor reusable, + // there's no DOR-SR issue here + QMetaObject::invokeMethod(q, "error", Qt::QueuedConnection, + Q_ARG(XMPP::StunTransaction::Error, StunTransaction::ErrorGeneric)); + return; + } + + StunMessage out = origMessage; + + out.setClass(StunMessage::Request); + id = QByteArray((const char *)out.id(), 12); + + if(!stuser.isEmpty()) + { + QList<StunMessage::Attribute> list = out.attributes(); + StunMessage::Attribute attr; + attr.type = StunTypes::USERNAME; + attr.value = StunTypes::createUsername(QString::fromUtf8(StunUtil::saslPrep(stuser.toUtf8()).toByteArray())); + list += attr; + out.setAttributes(list); + + key = StunUtil::saslPrep(stpass.toUtf8()).toByteArray(); + } + else if(!pool->d->nonce.isEmpty()) + { + QList<StunMessage::Attribute> list = out.attributes(); + { + StunMessage::Attribute attr; + attr.type = StunTypes::USERNAME; + attr.value = StunTypes::createUsername(QString::fromUtf8(StunUtil::saslPrep(pool->d->user.toUtf8()).toByteArray())); + list += attr; + } + { + StunMessage::Attribute attr; + attr.type = StunTypes::REALM; + attr.value = StunTypes::createRealm(pool->d->realm); + list += attr; + } + { + StunMessage::Attribute attr; + attr.type = StunTypes::NONCE; + attr.value = StunTypes::createNonce(pool->d->nonce); + list += attr; + } + out.setAttributes(list); + + QCA::SecureArray buf; + buf += StunUtil::saslPrep(pool->d->user.toUtf8()); + buf += QByteArray(1, ':'); + buf += StunUtil::saslPrep(pool->d->realm.toUtf8()); + buf += QByteArray(1, ':'); + buf += StunUtil::saslPrep(pool->d->pass); + + key = QCA::Hash("md5").process(buf).toByteArray(); + } + + if(!key.isEmpty()) + packet = out.toBinary(StunMessage::MessageIntegrity | StunMessage::Fingerprint, key); + else + packet = out.toBinary(StunMessage::Fingerprint); + + if(packet.isEmpty()) + { + // since a transaction is not cancelable nor reusable, + // there's no DOR-SR issue here + QMetaObject::invokeMethod(q, "error", Qt::QueuedConnection, + Q_ARG(XMPP::StunTransaction::Error, StunTransaction::ErrorGeneric)); + return; + } + + active = true; + tries = 1; // we transmit immediately here, so count it + + if(mode == StunTransaction::Udp) + { + last_interval = rm * rto; + t->start(rto); + rto *= 2; + } + else if(mode == StunTransaction::Tcp) + { + t->start(ti); + } + else + Q_ASSERT(0); + + time.start(); + pool->d->insert(q); + transmit(); + } + +private slots: + void t_timeout() + { + if(mode == StunTransaction::Tcp || tries == rc) + { + pool->d->remove(q); + emit q->error(StunTransaction::ErrorTimeout); + return; + } + + ++tries; + if(tries == rc) + { + t->start(last_interval); + } + else + { + t->start(rto); + rto *= 2; + } + + transmit(); + } + +private: + void transmit() + { + if(pool->d->debugLevel >= StunTransactionPool::DL_Packet) + { + QString str = QString("STUN SEND: elapsed=") + QString::number(time.elapsed()); + if(!to_addr.isNull()) + str += QString(" to=(") + to_addr.toString() + ';' + QString::number(to_port) + ')'; + emit pool->debugLine(str); + + StunMessage msg = StunMessage::fromBinary(packet); + emit pool->debugLine(StunTypes::print_packet_str(msg)); + } + + pool->d->transmit(q); + } + + bool checkActiveAndFrom(const QHostAddress &from_addr, int from_port) + { + if(!active) + return false; + + if(!to_addr.isNull() && (to_addr != from_addr || to_port != from_port)) + return false; + + return true; + } + + void processIncoming(const StunMessage &msg, bool authed) + { + active = false; + t->stop(); + + if(pool->d->debugLevel >= StunTransactionPool::DL_Packet) + emit pool->debugLine(QString("matched incoming response to existing request. elapsed=") + QString::number(time.elapsed())); + + // will be set to true when receiving an Unauthorized error + bool unauthError = false; + + if(msg.mclass() == StunMessage::ErrorResponse && pool->d->useLongTermAuth) + { + // we'll handle certain error codes at this layer + int code; + QString reason; + if(StunTypes::parseErrorCode(msg.attribute(StunTypes::ERROR_CODE), &code, &reason)) + { + if(code == StunTypes::Unauthorized) + unauthError = true; + + if(unauthError && !pool->d->triedLongTermAuth) + { + QString realm; + QString nonce; + if(StunTypes::parseRealm(msg.attribute(StunTypes::REALM), &realm) && + StunTypes::parseRealm(msg.attribute(StunTypes::NONCE), &nonce)) + { + // always set these to the latest received values, + // which will be used for all transactions + // once creds are provided. + if(pool->d->realm.isEmpty()) + pool->d->realm = realm; + pool->d->nonce = nonce; + + if(!pool->d->needLongTermAuth) + { + if(!pool->d->user.isEmpty()) + { + // creds already set? use them + pool->d->triedLongTermAuth = true; + retry(); + } + else + { + // else ask the user + pool->d->needLongTermAuth = true; + emit pool->needAuthParams(); + } + } + return; + } + } + else if(code == StunTypes::StaleNonce && pool->d->triedLongTermAuth) + { + QString nonce; + if(StunTypes::parseNonce(msg.attribute(StunTypes::NONCE), &nonce) && nonce != pool->d->nonce) + { + pool->d->nonce = nonce; + retry(); + return; + } + } + } + } + + // require message integrity when auth is used + if(!unauthError && (!stuser.isEmpty() || pool->d->triedLongTermAuth) && !authed) + return; + + pool->d->remove(q); + emit q->finished(msg); + } + +public: + bool writeIncomingMessage(const StunMessage &msg, const QHostAddress &from_addr, int from_port) + { + if(!checkActiveAndFrom(from_addr, from_port)) + return false; + + // if a StunMessage is passed directly to us then we assume + // the user has authenticated the message as necessary + processIncoming(msg, true); + return true; + } + + bool writeIncomingMessage(const QByteArray &packet, bool *notStun, const QHostAddress &from_addr, int from_port) + { + if(!checkActiveAndFrom(from_addr, from_port)) + { + // could be STUN, don't really know for sure + *notStun = false; + return false; + } + + int validationFlags = 0; + StunMessage msg = parse_stun_message(packet, &validationFlags, key); + if(msg.isNull()) + { + // packet doesn't parse at all, surely not STUN + *notStun = true; + return false; + } + + if(fpRequired && !(validationFlags & StunMessage::Fingerprint)) + { + // fingerprint failed when required. consider the + // packet to be surely not STUN + *notStun = true; + return false; + } + + processIncoming(msg, (validationFlags & StunMessage::MessageIntegrity) ? true : false); + return true; + } + +public slots: + void continueAfterParams() + { + retry(); + } +}; + +StunTransaction::StunTransaction(QObject *parent) : + QObject(parent) +{ + d = new StunTransactionPrivate(this); +} + +StunTransaction::~StunTransaction() +{ + delete d; +} + +void StunTransaction::start(StunTransactionPool *pool, const QHostAddress &toAddress, int toPort) +{ + Q_ASSERT(!d->active); + d->start(pool, toAddress, toPort); +} + +void StunTransaction::setMessage(const StunMessage &request) +{ + d->setMessage(request); +} + +void StunTransaction::setRTO(int i) +{ + Q_ASSERT(!d->active); + d->rto = i; +} + +void StunTransaction::setRc(int i) +{ + Q_ASSERT(!d->active); + d->rc = i; +} + +void StunTransaction::setRm(int i) +{ + Q_ASSERT(!d->active); + d->rm = i; +} + +void StunTransaction::setTi(int i) +{ + Q_ASSERT(!d->active); + d->ti = i; +} + +void StunTransaction::setShortTermUsername(const QString &username) +{ + d->stuser = username; +} + +void StunTransaction::setShortTermPassword(const QString &password) +{ + d->stpass = password; +} + +void StunTransaction::setFingerprintRequired(bool enabled) +{ + d->fpRequired = enabled; +} + +//---------------------------------------------------------------------------- +// StunTransactionPool +//---------------------------------------------------------------------------- +QByteArray StunTransactionPoolPrivate::generateId() const +{ + QByteArray id; + + do + { + id = QCA::Random::randomArray(12).toByteArray(); + } while(idToTrans.contains(id)); + + return id; +} + +void StunTransactionPoolPrivate::insert(StunTransaction *trans) +{ + Q_ASSERT(!trans->d->id.isEmpty()); + + transactions.insert(trans); + QByteArray id = trans->d->id; + transToId.insert(trans, id); + idToTrans.insert(id, trans); +} + +void StunTransactionPoolPrivate::remove(StunTransaction *trans) +{ + if(transactions.contains(trans)) + { + transactions.remove(trans); + QByteArray id = transToId.value(trans); + transToId.remove(trans); + idToTrans.remove(id); + } +} + +void StunTransactionPoolPrivate::transmit(StunTransaction *trans) +{ + emit q->outgoingMessage(trans->d->packet, trans->d->to_addr, trans->d->to_port); +} + +StunTransactionPool::StunTransactionPool(StunTransaction::Mode mode, QObject *parent) : + QObject(parent) +{ + d = new StunTransactionPoolPrivate(this); + d->mode = mode; +} + +StunTransactionPool::~StunTransactionPool() +{ + delete d; +} + +StunTransaction::Mode StunTransactionPool::mode() const +{ + return d->mode; +} + +bool StunTransactionPool::writeIncomingMessage(const StunMessage &msg, const QHostAddress &addr, int port) +{ + if(d->debugLevel >= DL_Packet) + { + QString str = "STUN RECV"; + if(!addr.isNull()) + str += QString(" from=(") + addr.toString() + ';' + QString::number(port) + ')'; + emit debugLine(str); + emit debugLine(StunTypes::print_packet_str(msg)); + } + + QByteArray id = QByteArray::fromRawData((const char *)msg.id(), 12); + StunMessage::Class mclass = msg.mclass(); + + if(mclass != StunMessage::SuccessResponse && mclass != StunMessage::ErrorResponse) + return false; + + StunTransaction *trans = d->idToTrans.value(id); + if(!trans) + return false; + + return trans->d->writeIncomingMessage(msg, addr, port); +} + +bool StunTransactionPool::writeIncomingMessage(const QByteArray &packet, bool *notStun, const QHostAddress &addr, int port) +{ + if(!StunMessage::isProbablyStun(packet)) + { + // basic stun check failed? surely not STUN + if(notStun) + *notStun = true; + return false; + } + + if(d->debugLevel >= DL_Packet) + { + StunMessage msg = StunMessage::fromBinary(packet); + QString str = "STUN RECV"; + if(!addr.isNull()) + str += QString(" from=(") + addr.toString() + ';' + QString::number(port) + ')'; + emit debugLine(str); + emit debugLine(StunTypes::print_packet_str(msg)); + } + + // isProbablyStun ensures the packet is 20 bytes long, so we can safely + // safely extract out the transaction id from the raw packet + QByteArray id = QByteArray((const char *)packet.data() + 8, 12); + + StunMessage::Class mclass = StunMessage::extractClass(packet); + + if(mclass != StunMessage::SuccessResponse && mclass != StunMessage::ErrorResponse) + { + // could be STUN, don't really know for sure + if(notStun) + *notStun = false; + return false; + } + + StunTransaction *trans = d->idToTrans.value(id); + if(!trans) + { + // could be STUN, don't really know for sure + if(notStun) + *notStun = false; + return false; + } + + bool _notStun = false; + bool ret = trans->d->writeIncomingMessage(packet, &_notStun, addr, port); + if(!ret && notStun) + *notStun = _notStun; + return ret; +} + +void StunTransactionPool::setLongTermAuthEnabled(bool enabled) +{ + d->useLongTermAuth = enabled; +} + +QString StunTransactionPool::realm() const +{ + return d->realm; +} + +void StunTransactionPool::setUsername(const QString &username) +{ + d->user = username; +} + +void StunTransactionPool::setPassword(const QCA::SecureArray &password) +{ + d->pass = password; +} + +void StunTransactionPool::setRealm(const QString &realm) +{ + d->realm = realm; +} + +void StunTransactionPool::continueAfterParams() +{ + if(d->debugLevel >= DL_Info) + { + emit debugLine("continue after params:"); + emit debugLine(QString(" U=%1").arg(d->user)); + emit debugLine(QString(" P=%1").arg(d->pass.data())); + emit debugLine(QString(" R=%1").arg(d->realm)); + emit debugLine(QString(" N=%1").arg(d->nonce)); + } + + Q_ASSERT(d->useLongTermAuth); + Q_ASSERT(d->needLongTermAuth); + Q_ASSERT(!d->triedLongTermAuth); + + d->needLongTermAuth = false; + d->triedLongTermAuth = true; + + foreach(StunTransaction *trans, d->transactions) + { + // the only reason an inactive transaction would be in the + // list is if it is waiting for an auth retry + if(!trans->d->active) + { + // use queued call to prevent all sorts of DOR-SS + // nastiness + QMetaObject::invokeMethod(trans->d, "continueAfterParams", + Qt::QueuedConnection); + } + } +} + +QByteArray StunTransactionPool::generateId() const +{ + return d->generateId(); +} + +void StunTransactionPool::setDebugLevel(DebugLevel level) +{ + d->debugLevel = level; +} + +} + +#include "stuntransaction.moc"
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stuntransaction.h
Added
@@ -0,0 +1,207 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef STUNTRANSACTION_H +#define STUNTRANSACTION_H + +#include <QObject> +#include <QByteArray> +#include <QHostAddress> + +namespace QCA { + class SecureArray; +} + +namespace XMPP { + +class StunMessage; + +class StunTransactionPrivate; +class StunTransactionPool; +class StunTransactionPoolPrivate; + +// Notes: +// +// - we allow multiple simultaneous requests. no serializing or waiting, at +// least not at the transaction layer. +// - requests may require authentication. the protocol flow for STUN is that +// you first try a request without providing credentials, and if +// authentication is needed then an error is returned. the request must be +// tried again with credentials provided for it to succeed. note that the +// error response contains a nonce value that must be passed back in the +// second request, and so the first request cannot be skipped. +// - it is possible to provide credentials in advance, so that the user is not +// asked for them dynamically. however, the protocol flow remains the same +// either way (i.e. request w/o creds, error, request with creds). +// - the user is only asked for credentials once ever. if two requests require +// authentication, the user is asked only once and both requests will be +// retried once the creds are provided. if an authentication error is +// received after providing creds, then the transaction will fail. this +// means the user only has one chance to get the creds right, and creds +// cannot change during a session. in the event of failure due to wrong or +// changed creds, the pool will need to be recreated in order to try new +// creds. +// - if short term or long term auth is used, then the request is authenticated +// and the response is required to be authenticated. + +class StunTransaction : public QObject +{ + Q_OBJECT + +public: + enum Mode + { + Udp, // handle retransmissions + Tcp // send once + }; + + enum Error + { + ErrorGeneric, + ErrorTimeout + }; + + StunTransaction(QObject *parent = 0); + ~StunTransaction(); + + // toAddress/toPort are optional, to associate this request to a + // specific endpoint + // note: not DOR-DS safe. this function will cause the pool's + // outgoingMessage() signal to be emitted. + void start(StunTransactionPool *pool, const QHostAddress &toAddress = QHostAddress(), int toPort = -1); + + // pass message with class unset. use transaction id from the + // createMessage signal. + void setMessage(const StunMessage &request); + + // transmission/timeout parameters, from RFC 5389. by default, + // they are set to the recommended values from the RFC. + void setRTO(int i); + void setRc(int i); + void setRm(int i); + void setTi(int i); + + void setShortTermUsername(const QString &username); + void setShortTermPassword(const QString &password); + + // fingerprint is always provided in outbound requests, but ignored + // on responses. if this flag is set, then responses will be + // required to provide a fingerprint. + void setFingerprintRequired(bool enabled); + +signals: + // you must use a direct connection with this signal and call + // setMessage() in the slot. this signal may occur many times + // before the StunTransaction completes, and you must recreate the + // message every time using the new transactionId. + void createMessage(const QByteArray &transactionId); + + void finished(const XMPP::StunMessage &response); + void error(XMPP::StunTransaction::Error error); + +private: + Q_DISABLE_COPY(StunTransaction) + + friend class StunTransactionPool; + friend class StunTransactionPoolPrivate; + + friend class StunTransactionPrivate; + StunTransactionPrivate *d; +}; + +// keep track of many open transactions. note that retransmit() may be +// emitted as a direct result of calling certain member functions of this +// class as well as any other class that might use it (such as StunBinding). +// so, be careful with what you do in your retransmit slot. +class StunTransactionPool : public QObject +{ + Q_OBJECT + +public: + enum DebugLevel + { + DL_None, + DL_Info, + DL_Packet + }; + + StunTransactionPool(StunTransaction::Mode mode, QObject *parent = 0); + ~StunTransactionPool(); + + StunTransaction::Mode mode() const; + + // note: the writeIncomingMessage functions are not DOR-DS safe. they + // may cause a transaction to emit finished() or error() signals. + + // returns true if the message is owned by the pool, else false. + bool writeIncomingMessage(const StunMessage &msg, const QHostAddress &addr = QHostAddress(), int port = -1); + + // returns true if the packet is surely a STUN message and owned by the + // pool, else false. a packet must be owned by the pool to be + // considered surely a STUN message. if false, the packet may or may + // not be a STUN message. *notStun will be set to true if the packet + // is surely not STUN, or set to false if it is unclear whether the + // packet is STUN or not. + bool writeIncomingMessage(const QByteArray &packet, bool *notStun = 0, const QHostAddress &addr = QHostAddress(), int port = -1); + + void setLongTermAuthEnabled(bool enabled); + + QString realm() const; + void setUsername(const QString &username); + void setPassword(const QCA::SecureArray &password); + void setRealm(const QString &realm); + void continueAfterParams(); + + // for use with stun indications + QByteArray generateId() const; + + void setDebugLevel(DebugLevel level); // default DL_None + +signals: + // note: not DOR-SS safe. writeIncomingMessage() must not be called + // during this signal. + // + // why do we need this restriction? long explanation: since + // outgoingMessage() can be emitted as a result of calling a + // transaction's start(), and calling writeIncomingMessage() could + // result in a transaction completing, then calling + // writeIncomingMessage() during outgoingMessage() could cause + // a transaction's finished() or error() signals to emit during + // start(), which would violate DOR-DS. + void outgoingMessage(const QByteArray &packet, const QHostAddress &addr, int port); + + void needAuthParams(); + + // not DOR-SS/DS safe + void debugLine(const QString &line); + +private: + Q_DISABLE_COPY(StunTransactionPool) + + friend class StunTransaction; + friend class StunTransactionPrivate; + + friend class StunTransactionPoolPrivate; + StunTransactionPoolPrivate *d; +}; + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stuntypes.cpp
Added
@@ -0,0 +1,738 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "stuntypes.h" + +#include <stdio.h> +#include <QtCrypto> +#include "stunutil.h" + +#define STRING_MAX_CHARS 127 +#define STRING_MAX_BYTES 763 + +namespace XMPP { + +using namespace StunUtil; + +namespace StunTypes { + +static void xorIPv4(QByteArray *in, const quint8 *magic) +{ + quint8 *p = (quint8 *)in->data(); + p2 ^= magic0; + p3 ^= magic1; + for(int n = 0; n < 4; ++n) + pn + 4 ^= magicn; +} + +static void xorIPv6(QByteArray *in, const quint8 *magic, const quint8 *id) +{ + quint8 *p = (quint8 *)in->data(); + p2 ^= magic0; + p3 ^= magic1; + for(int n = 0; n < 4; ++n) + pn + 4 ^= magicn; + for(int n = 0; n < 12; ++n) + pn + 8 ^= idn; +} + +static bool validateString(const QByteArray &in, QString *out) +{ + if(in.size() <= STRING_MAX_BYTES) + { + QString s = QString::fromUtf8(in); + if(s.length() <= STRING_MAX_CHARS) + { + *out = s; + return true; + } + } + + return false; +} + +QByteArray createMappedAddress(const QHostAddress &addr, quint16 port) +{ + QByteArray out; + + if(addr.protocol() == QAbstractSocket::IPv6Protocol) + { + out = QByteArray(20, 0); + out1 = 0x02; // IPv6 + Q_IPV6ADDR addr6 = addr.toIPv6Address(); + memcpy(out.data() + 4, addr6.c, 16); + } + else if(addr.protocol() == QAbstractSocket::IPv4Protocol) + { + out = QByteArray(8, 0); + out1 = 0x01; // IPv4 + write32((quint8 *)out.data() + 4, addr.toIPv4Address()); + } + else + Q_ASSERT(0); + + write16((quint8 *)out.data() + 2, port); + return out; +} + +QByteArray createUsername(const QString &username) +{ + return username.left(STRING_MAX_CHARS).toUtf8(); +} + +QByteArray createErrorCode(int code, const QString &reason) +{ + QByteArray out(4, 0); + + int ih = code / 100; + int il = code % 100; + ih &= 0x07; // keep only lower 3 bits + + unsigned char ch = (unsigned char)ih; + unsigned char cl = (unsigned char)il; + out2 = ch; + out3 = cl; + out += reason.left(STRING_MAX_CHARS).toUtf8(); + return out; +} + +QByteArray createUnknownAttributes(const QList<quint16> &typeList) +{ + if(typeList.isEmpty()) + return QByteArray(); + + QByteArray out(typeList.count() * 2, 0); + for(int n = 0; n < typeList.count(); ++n) + write16((quint8 *)out.data() + (n * 2), typeListn); + return out; +} + +QByteArray createRealm(const QString &realm) +{ + return realm.left(STRING_MAX_CHARS).toUtf8(); +} + +QByteArray createNonce(const QString &nonce) +{ + return nonce.left(STRING_MAX_CHARS).toUtf8(); +} + +QByteArray createXorMappedAddress(const QHostAddress &addr, quint16 port, const quint8 *magic, const quint8 *id) +{ + QByteArray out = createMappedAddress(addr, port); + if(addr.protocol() == QAbstractSocket::IPv6Protocol) + xorIPv6(&out, magic, id); + else // IPv4 + xorIPv4(&out, magic); + return out; +} + +QByteArray createChannelNumber(quint16 i) +{ + QByteArray val(4, 0); + write16((quint8 *)val.data(), i); + // bytes 2-3 are zeroed out + return val; +} + +QByteArray createLifetime(quint32 i) +{ + QByteArray val(4, 0); + write32((quint8 *)val.data(), i); + return val; +} + +QByteArray createXorPeerAddress(const QHostAddress &addr, quint16 port, const quint8 *magic, const quint8 *id) +{ + return createXorMappedAddress(addr, port, magic, id); +} + +QByteArray createXorRelayedAddress(const QHostAddress &addr, quint16 port, const quint8 *magic, const quint8 *id) +{ + return createXorMappedAddress(addr, port, magic, id); +} + +QByteArray createEvenPort(bool reserve) +{ + QByteArray val(1, 0); + unsigned char c = 0; + if(reserve) + c |= 0x80; // set high bit + val0 = c; + return val; +} + +QByteArray createRequestedTransport(quint8 proto) +{ + QByteArray val(4, 0); + val0 = proto; + // bytes 1-3 are zeroed out + return val; +} + +QByteArray createReservationToken(const QByteArray &token) +{ + Q_ASSERT(token.size() == 8); + return token; +} + +QByteArray createPriority(quint32 i) +{ + QByteArray val(4, 0); + write32((quint8 *)val.data(), i); + return val; +} + +QByteArray createSoftware(const QString &str) +{ + return str.left(STRING_MAX_CHARS).toUtf8(); +} + +QByteArray createAlternateServer(const QHostAddress &addr, quint16 port) +{ + return createMappedAddress(addr, port); +} + +QByteArray createIceControlled(quint64 i) +{ + QByteArray val(8, 0); + write64((quint8 *)val.data(), i); + return val; +} + +QByteArray createIceControlling(quint64 i) +{ + QByteArray val(8, 0); + write64((quint8 *)val.data(), i); + return val; +} + +bool parseMappedAddress(const QByteArray &val, QHostAddress *addr, quint16 *port) +{ + if(val1 == 0x02 && val.size() == 20) // IPv6 + { + *port = read16((const quint8 *)val.data() + 2); + QByteArray buf = val.mid(4); + *addr = QHostAddress((quint8 *)buf.data()); + return true; + } + else if(val1 == 0x01 && val.size() == 8) // IPv4 + { + *port = read16((const quint8 *)val.data() + 2); + *addr = QHostAddress(read32((const quint8 *)val.data() + 4)); + return true; + } + else + return false; +} + +bool parseUsername(const QByteArray &val, QString *username) +{ + return validateString(val, username); +} + +bool parseErrorCode(const QByteArray &val, int *code, QString *reason) +{ + if(val.size() < 4) + return false; + + unsigned char ch = (unsigned char)val2; + unsigned char cl = (unsigned char)val3; + int ih = ch & 0x07; // lower 3 bits + int x = ih * 100 + (int)cl; + + QString str; + if(validateString(val.mid(4), &str)) + { + *code = x; + *reason = str; + return true; + } + + return false; +} + +bool parseUnknownAttributes(const QByteArray &val, QList<quint16> *typeList) +{ + if(val.size() % 2 != 0) + return false; + + typeList->clear(); + int count = val.size() / 2; + for(int n = 0; n < count; ++n) + typeList->append(read16((const quint8 *)val.data() + (n * 2))); + return true; +} + +bool parseRealm(const QByteArray &val, QString *realm) +{ + return validateString(val, realm); +} + +bool parseNonce(const QByteArray &val, QString *nonce) +{ + return validateString(val, nonce); +} + +bool parseXorMappedAddress(const QByteArray &val, const quint8 *magic, const quint8 *id, QHostAddress *addr, quint16 *port) +{ + if(val.size() < 4) + return false; + + QByteArray buf; + if(val1 == 0x02 && val.size() == 20) // IPv6 + { + buf = val; + xorIPv6(&buf, magic, id); + } + else if(val1 == 0x01 && val.size() == 8) // IPv4 + { + buf = val; + xorIPv4(&buf, magic); + } + else + return false; + + return parseMappedAddress(buf, addr, port); +} + +bool parseChannelNumber(const QByteArray &val, quint16 *i) +{ + if(val.size() != 4) + return false; + + const quint8 *p = (const quint8 *)val.data(); + *i = read16(p); + return true; +} + +bool parseLifetime(const QByteArray &val, quint32 *i) +{ + if(val.size() != 4) + return false; + + const quint8 *p = (const quint8 *)val.data(); + *i = read32(p); + return true; +} + +bool parseXorPeerAddress(const QByteArray &val, const quint8 *magic, const quint8 *id, QHostAddress *addr, quint16 *port) +{ + return parseXorMappedAddress(val, magic, id, addr, port); +} + +bool parseXorRelayedAddress(const QByteArray &val, const quint8 *magic, const quint8 *id, QHostAddress *addr, quint16 *port) +{ + return parseXorMappedAddress(val, magic, id, addr, port); +} + +bool parseEvenPort(const QByteArray &val, bool *reserve) +{ + if(val.size() != 1) + return false; + + unsigned char c = val0; + if(c & 0x80) + *reserve = true; + else + *reserve = false; + + return true; +} + +bool parseRequestedTransport(const QByteArray &val, quint8 *proto) +{ + if(val.size() != 4) + return false; + + *proto = val0; + return true; +} + +bool parseReservationToken(const QByteArray &val, QByteArray *token) +{ + if(val.size() != 8) + return false; + + *token = val; + return true; +} + +bool parsePriority(const QByteArray &val, quint32 *i) +{ + if(val.size() != 4) + return false; + + const quint8 *p = (const quint8 *)val.data(); + *i = read32(p); + return true; +} + +bool parseSoftware(const QByteArray &val, QString *str) +{ + *str = QString::fromUtf8(val); + return true; +} + +bool parseAlternateServer(const QByteArray &val, QHostAddress *addr, quint16 *port) +{ + return parseMappedAddress(val, addr, port); +} + +bool parseIceControlled(const QByteArray &val, quint64 *i) +{ + if(val.size() != 8) + return false; + + const quint8 *p = (const quint8 *)val.data(); + *i = read64(p); + return true; +} + +bool parseIceControlling(const QByteArray &val, quint64 *i) +{ + if(val.size() != 8) + return false; + + const quint8 *p = (const quint8 *)val.data(); + *i = read64(p); + return true; +} + +#define METHOD_ENTRY(x) \ + { x, #x } + +struct MethodEntry +{ + Method method; + const char *str; +} method_table = +{ + METHOD_ENTRY(Binding), + METHOD_ENTRY(Allocate), + METHOD_ENTRY(Refresh), + METHOD_ENTRY(Send), + METHOD_ENTRY(Data), + METHOD_ENTRY(CreatePermission), + METHOD_ENTRY(ChannelBind), + { (Method)-1, 0 } +}; + +QString methodToString(int method) +{ + for(int n = 0; method_tablen.str; ++n) + { + if(method_tablen.method == (Method)method) + return QString::fromLatin1(method_tablen.str); + } + + return QString(); +} + +#define ATTRIB_ENTRY(x) \ + { x, #x } + +struct AttribEntry +{ + Attribute type; + const char *str; +} attrib_table = +{ + ATTRIB_ENTRY(MAPPED_ADDRESS), + ATTRIB_ENTRY(USERNAME), + ATTRIB_ENTRY(MESSAGE_INTEGRITY), + ATTRIB_ENTRY(ERROR_CODE), + ATTRIB_ENTRY(UNKNOWN_ATTRIBUTES), + ATTRIB_ENTRY(REALM), + ATTRIB_ENTRY(NONCE), + ATTRIB_ENTRY(XOR_MAPPED_ADDRESS), + ATTRIB_ENTRY(CHANNEL_NUMBER), + ATTRIB_ENTRY(LIFETIME), + ATTRIB_ENTRY(XOR_PEER_ADDRESS), + ATTRIB_ENTRY(DATA), + ATTRIB_ENTRY(XOR_RELAYED_ADDRESS), + ATTRIB_ENTRY(EVEN_PORT), + ATTRIB_ENTRY(REQUESTED_TRANSPORT), + ATTRIB_ENTRY(DONT_FRAGMENT), + ATTRIB_ENTRY(RESERVATION_TOKEN), + ATTRIB_ENTRY(PRIORITY), + ATTRIB_ENTRY(USE_CANDIDATE), + ATTRIB_ENTRY(SOFTWARE), + ATTRIB_ENTRY(ALTERNATE_SERVER), + ATTRIB_ENTRY(FINGERPRINT), + ATTRIB_ENTRY(ICE_CONTROLLED), + ATTRIB_ENTRY(ICE_CONTROLLING), + { (Attribute)-1, 0 } +}; + +QString attributeTypeToString(int type) +{ + for(int n = 0; attrib_tablen.str; ++n) + { + if(attrib_tablen.type == (Attribute)type) + { + QString name = QString::fromLatin1(attrib_tablen.str); + name.replace('_', '-'); + return name; + } + } + + return QString(); +} + +static QString quoted(const QString &in) +{ + return QString("\"") + in + '\"'; +} + +QString attributeValueToString(int type, const QByteArray &val, const quint8 *magic, const quint8 *id) +{ + switch((Attribute)type) + { + case MAPPED_ADDRESS: + { + QHostAddress addr; + quint16 port; + if(parseMappedAddress(val, &addr, &port)) + return addr.toString() + ';' + QString::number(port); + break; + } + case USERNAME: + { + QString str; + if(parseUsername(val, &str)) + return quoted(str); + break; + } + case MESSAGE_INTEGRITY: + { + return QCA::arrayToHex(val); + } + case ERROR_CODE: + { + int code; + QString reason; + if(parseErrorCode(val, &code, &reason)) + { + QString out = QString::number(code); + if(!reason.isEmpty()) + out += QString(", ") + quoted(reason); + return out; + } + break; + } + case UNKNOWN_ATTRIBUTES: + { + QList<quint16> typeList; + if(parseUnknownAttributes(val, &typeList)) + { + if(!typeList.isEmpty()) + { + QStringList strList; + foreach(quint16 i, typeList) + strList += QString().sprintf("0x%04x", i); + return strList.join(", "); + } + else + return "(None)"; + } + break; + } + case REALM: + { + QString str; + if(parseRealm(val, &str)) + return quoted(str); + break; + } + case NONCE: + { + QString str; + if(parseNonce(val, &str)) + return quoted(str); + break; + } + case XOR_MAPPED_ADDRESS: + { + QHostAddress addr; + quint16 port; + if(parseXorMappedAddress(val, magic, id, &addr, &port)) + return addr.toString() + ';' + QString::number(port); + break; + } + case CHANNEL_NUMBER: + { + quint16 i; + if(parseChannelNumber(val, &i)) + return QString().sprintf("0x%04x", (int)i); + break; + } + case LIFETIME: + { + quint32 i; + if(parseLifetime(val, &i)) + return QString::number(i); + break; + } + case XOR_PEER_ADDRESS: + { + return attributeValueToString(XOR_MAPPED_ADDRESS, val, magic, id); + } + case DATA: + { + return QString("len=%1, ").arg(val.size()) + QCA::arrayToHex(val); + } + case XOR_RELAYED_ADDRESS: + { + return attributeValueToString(XOR_MAPPED_ADDRESS, val, magic, id); + } + case EVEN_PORT: + { + bool reserve; + if(parseEvenPort(val, &reserve)) + return QString("reserve=") + (reserve ? "true" : "false"); + break; + } + case REQUESTED_TRANSPORT: + { + quint8 proto; + if(parseRequestedTransport(val, &proto)) + { + QString str = QString::number((int)proto); + if(proto == 17) // UDP + str += " (UDP)"; + else + str += " (Unknown)"; + return str; + } + break; + } + case DONT_FRAGMENT: + { + return QString(""); + } + case RESERVATION_TOKEN: + { + QByteArray token; + if(parseReservationToken(val, &token)) + return QCA::arrayToHex(token); + break; + } + case PRIORITY: + { + quint32 i; + if(parsePriority(val, &i)) + return QString::number(i); + break; + } + case USE_CANDIDATE: + { + return QString(""); + } + case SOFTWARE: + { + QString out; + if(parseSoftware(val, &out)) + return quoted(out); + break; + } + case ALTERNATE_SERVER: + { + return attributeValueToString(MAPPED_ADDRESS, val, magic, id); + } + case FINGERPRINT: + { + return QCA::arrayToHex(val); + } + case ICE_CONTROLLED: + { + quint64 i; + if(parseIceControlled(val, &i)) + return QString::number(i); + break; + } + case ICE_CONTROLLING: + { + quint64 i; + if(parseIceControlling(val, &i)) + return QString::number(i); + break; + } + } + + return QString(); +} + +QString print_packet_str(const StunMessage &message) +{ + QString out; + + QString mclass; + if(message.mclass() == StunMessage::Request) + mclass = "Request"; + else if(message.mclass() == StunMessage::SuccessResponse) + mclass = "Response (Success)"; + else if(message.mclass() == StunMessage::ErrorResponse) + mclass = "Response (Error)"; + else if(message.mclass() == StunMessage::Indication) + mclass = "Indication"; + else + Q_ASSERT(0); + + out += QString("Class: %1\n").arg(mclass); + out += QString("Method: %1\n").arg(methodToString(message.method())); + out += QString("Transaction id: %1\n").arg(QCA::arrayToHex(QByteArray((const char *)message.id(), 12))); + out += "Attributes:"; + QList<StunMessage::Attribute> attribs = message.attributes(); + if(!attribs.isEmpty()) + { + foreach(const StunMessage::Attribute &a, attribs) + { + out += '\n'; + + QString name = attributeTypeToString(a.type); + if(!name.isNull()) + { + QString val = attributeValueToString(a.type, a.value, message.magic(), message.id()); + if(val.isNull()) + val = QString("Unable to parse %1 bytes").arg(a.value.size()); + + out += QString(" %1").arg(name); + if(!val.isEmpty()) + out += QString(" = %1").arg(val); + } + else + out += QString().sprintf(" Unknown attribute (0x%04x) of %d bytes", a.type, a.value.size()); + } + } + else + out += "\n (None)"; + + return out; +} + +void print_packet(const StunMessage &message) +{ + printf("%s\n", qPrintable(print_packet_str(message))); +} + +} + +}
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stuntypes.h
Added
@@ -0,0 +1,146 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef STUNTYPES_H +#define STUNTYPES_H + +#include <QString> +#include <QByteArray> +#include <QList> +#include <QHostAddress> +#include "stunmessage.h" + +namespace XMPP { + +namespace StunTypes { + +enum Method +{ + Binding = 0x001, + Allocate = 0x003, + Refresh = 0x004, + Send = 0x006, + Data = 0x007, + CreatePermission = 0x008, + ChannelBind = 0x009 +}; + +enum Attribute +{ + MAPPED_ADDRESS = 0x0001, + USERNAME = 0x0006, + MESSAGE_INTEGRITY = 0x0008, + ERROR_CODE = 0x0009, + UNKNOWN_ATTRIBUTES = 0x000a, + REALM = 0x0014, + NONCE = 0x0015, + XOR_MAPPED_ADDRESS = 0x0020, + CHANNEL_NUMBER = 0x000c, + LIFETIME = 0x000d, + XOR_PEER_ADDRESS = 0x0012, + DATA = 0x0013, + XOR_RELAYED_ADDRESS = 0x0016, + EVEN_PORT = 0x0018, + REQUESTED_TRANSPORT = 0x0019, + DONT_FRAGMENT = 0x001a, + RESERVATION_TOKEN = 0x0022, + + PRIORITY = 0x0024, + USE_CANDIDATE = 0x0025, + + SOFTWARE = 0x8022, + ALTERNATE_SERVER = 0x8023, + FINGERPRINT = 0x8028, + + ICE_CONTROLLED = 0x8029, + ICE_CONTROLLING = 0x802a +}; + +enum Error +{ + TryAlternate = 300, + BadRequest = 400, + Unauthorized = 401, + UnknownAttribute = 420, + StaleNonce = 438, + ServerError = 500, + + Forbidden = 403, + AllocationMismatch = 437, + WrongCredentials = 441, + UnsupportedTransportProtocol = 442, + AllocationQuotaReached = 486, + InsufficientCapacity = 508, + + RoleConflict = 487 +}; + +QByteArray createMappedAddress(const QHostAddress &addr, quint16 port); +QByteArray createUsername(const QString &username); +QByteArray createErrorCode(int code, const QString &reason); +QByteArray createUnknownAttributes(const QList<quint16> &typeList); +QByteArray createRealm(const QString &realm); +QByteArray createNonce(const QString &nonce); +QByteArray createXorMappedAddress(const QHostAddress &addr, quint16 port, const quint8 *magic, const quint8 *id); +QByteArray createChannelNumber(quint16 i); +QByteArray createLifetime(quint32 i); +QByteArray createXorPeerAddress(const QHostAddress &addr, quint16 port, const quint8 *magic, const quint8 *id); +QByteArray createXorRelayedAddress(const QHostAddress &addr, quint16 port, const quint8 *magic, const quint8 *id); +QByteArray createEvenPort(bool reserve); +QByteArray createRequestedTransport(quint8 proto); +QByteArray createReservationToken(const QByteArray &token); +QByteArray createPriority(quint32 i); +QByteArray createSoftware(const QString &str); +QByteArray createAlternateServer(const QHostAddress &addr, quint16 port); +QByteArray createIceControlled(quint64 i); +QByteArray createIceControlling(quint64 i); + +bool parseMappedAddress(const QByteArray &val, QHostAddress *addr, quint16 *port); +bool parseUsername(const QByteArray &val, QString *username); +bool parseErrorCode(const QByteArray &val, int *code, QString *reason); +bool parseUnknownAttributes(const QByteArray &val, QList<quint16> *typeList); +bool parseRealm(const QByteArray &val, QString *realm); +bool parseNonce(const QByteArray &val, QString *nonce); +bool parseXorMappedAddress(const QByteArray &val, const quint8 *magic, const quint8 *id, QHostAddress *addr, quint16 *port); +bool parseChannelNumber(const QByteArray &val, quint16 *i); +bool parseLifetime(const QByteArray &val, quint32 *i); +bool parseXorPeerAddress(const QByteArray &val, const quint8 *magic, const quint8 *id, QHostAddress *addr, quint16 *port); +bool parseXorRelayedAddress(const QByteArray &val, const quint8 *magic, const quint8 *id, QHostAddress *addr, quint16 *port); +bool parseEvenPort(const QByteArray &val, bool *reserve); +bool parseRequestedTransport(const QByteArray &val, quint8 *proto); +bool parseReservationToken(const QByteArray &val, QByteArray *token); +bool parsePriority(const QByteArray &val, quint32 *i); +bool parseSoftware(const QByteArray &val, QString *str); +bool parseAlternateServer(const QByteArray &val, QHostAddress *addr, quint16 *port); +bool parseIceControlled(const QByteArray &val, quint64 *i); +bool parseIceControlling(const QByteArray &val, quint64 *i); + +QString methodToString(int method); +QString attributeTypeToString(int type); +QString attributeValueToString(int type, const QByteArray &val, const quint8 *magic, const quint8 *id); + +QString print_packet_str(const StunMessage &message); +void print_packet(const StunMessage &message); + +} + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stunutil.cpp
Added
@@ -0,0 +1,101 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "stunutil.h" + +namespace XMPP { + +namespace StunUtil { + +quint16 read16(const quint8 *in) +{ + quint16 out = in0; + out <<= 8; + out += in1; + return out; +} + +quint32 read32(const quint8 *in) +{ + quint32 out = in0; + out <<= 8; + out += in1; + out <<= 8; + out += in2; + out <<= 8; + out += in3; + return out; +} + +quint64 read64(const quint8 *in) +{ + quint64 out = in0; + out <<= 8; + out += in1; + out <<= 8; + out += in2; + out <<= 8; + out += in3; + out <<= 8; + out += in4; + out <<= 8; + out += in5; + out <<= 8; + out += in6; + out <<= 8; + out += in7; + return out; +} + +void write16(quint8 *out, quint16 i) +{ + out0 = (i >> 8) & 0xff; + out1 = i & 0xff; +} + +void write32(quint8 *out, quint32 i) +{ + out0 = (i >> 24) & 0xff; + out1 = (i >> 16) & 0xff; + out2 = (i >> 8) & 0xff; + out3 = i & 0xff; +} + +void write64(quint8 *out, quint64 i) +{ + out0 = (i >> 56) & 0xff; + out1 = (i >> 48) & 0xff; + out2 = (i >> 40) & 0xff; + out3 = (i >> 32) & 0xff; + out4 = (i >> 24) & 0xff; + out5 = (i >> 16) & 0xff; + out6 = (i >> 8) & 0xff; + out7 = i & 0xff; +} + +QCA::SecureArray saslPrep(const QCA::SecureArray &in) +{ + // TODO + return in; +} + +} + +}
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/stunutil.h
Added
@@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef STUNUTIL_H +#define STUNUTIL_H + +#include <QtCrypto> + +namespace XMPP { + +namespace StunUtil { + +quint16 read16(const quint8 *in); +quint32 read32(const quint8 *in); +quint64 read64(const quint8 *in); + +void write16(quint8 *out, quint16 i); +void write32(quint8 *out, quint32 i); +void write64(quint8 *out, quint64 i); + +QCA::SecureArray saslPrep(const QCA::SecureArray &in); + +} + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/turnclient.cpp
Added
@@ -0,0 +1,1147 @@ +/* + * Copyright (C) 2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "turnclient.h" + +#include <QtCrypto> +#include "stuntypes.h" +#include "stunmessage.h" +#include "stuntransaction.h" +#include "stunallocate.h" +#include "objectsession.h" +#include "bytestream.h" +#include "bsocket.h" +#include "httpconnect.h" +#include "socks.h" + +namespace XMPP { + +//---------------------------------------------------------------------------- +// TurnClient::Proxy +//---------------------------------------------------------------------------- +TurnClient::Proxy::Proxy() +{ + t = None; +} + +TurnClient::Proxy::~Proxy() +{ +} + +int TurnClient::Proxy::type() const +{ + return t; +} + +QString TurnClient::Proxy::host() const +{ + return v_host; +} + +quint16 TurnClient::Proxy::port() const +{ + return v_port; +} + +QString TurnClient::Proxy::user() const +{ + return v_user; +} + +QString TurnClient::Proxy::pass() const +{ + return v_pass; +} + +void TurnClient::Proxy::setHttpConnect(const QString &host, quint16 port) +{ + t = HttpConnect; + v_host = host; + v_port = port; +} + +void TurnClient::Proxy::setSocks(const QString &host, quint16 port) +{ + t = Socks; + v_host = host; + v_port = port; +} + +void TurnClient::Proxy::setUserPass(const QString &user, const QString &pass) +{ + v_user = user; + v_pass = pass; +} + +//---------------------------------------------------------------------------- +// TurnClient +//---------------------------------------------------------------------------- +class TurnClient::Private : public QObject +{ + Q_OBJECT + +public: + TurnClient *q; + Proxy proxy; + QString clientSoftware; + TurnClient::Mode mode; + QHostAddress serverAddr; + int serverPort; + ObjectSession sess; + ByteStream *bs; + QCA::TLS *tls; + bool tlsHandshaken; + QByteArray inStream; + bool udp; + StunTransactionPool *pool; + StunAllocate *allocate; + bool allocateStarted; + QString user; + QCA::SecureArray pass; + QString realm; + int retryCount; + QString errorString; + int debugLevel; + + class WriteItem + { + public: + enum Type + { + Data, + Other + }; + + Type type; + int size; + QHostAddress addr; + int port; + + WriteItem(int _size) : + type(Other), + size(_size), + port(-1) + { + } + + WriteItem(int _size, const QHostAddress &_addr, int _port) : + type(Data), + size(_size), + addr(_addr), + port(_port) + { + } + }; + + QList<WriteItem> writeItems; + int writtenBytes; + bool stopping; + + class Packet + { + public: + QHostAddress addr; + int port; + QByteArray data; + + // for outbound + bool requireChannel; + + Packet() : + port(-1), + requireChannel(false) + { + } + }; + + QList<Packet> in; + QList<Packet> outPending; + int outPendingWrite; + QList<QHostAddress> desiredPerms; + QList<StunAllocate::Channel> pendingChannels, desiredChannels; + + class Written + { + public: + QHostAddress addr; + int port; + int count; + }; + + Private(TurnClient *_q) : + QObject(_q), + q(_q), + sess(this), + bs(0), + tls(0), + udp(false), + pool(0), + allocate(0), + retryCount(0), + debugLevel(TurnClient::DL_None), + writtenBytes(0), + stopping(false), + outPendingWrite(0) + { + } + + ~Private() + { + cleanup(); + } + + void cleanup() + { + delete allocate; + allocate = 0; + + // in udp mode, we don't own the pool + if(!udp) + delete pool; + pool = 0; + + delete tls; + tls = 0; + + delete bs; + bs = 0; + + udp = false; + + sess.reset(); + + inStream.clear(); + retryCount = 0; + writeItems.clear(); + writtenBytes = 0; + stopping = false; + outPending.clear(); + outPendingWrite = 0; + desiredPerms.clear(); + pendingChannels.clear(); + desiredChannels.clear(); + } + + void do_connect() + { + if(udp) + { + after_connected(); + return; + } + + if(proxy.type() == Proxy::HttpConnect) + { + HttpConnect *s = new HttpConnect(this); + bs = s; + connect(s, SIGNAL(connected()), SLOT(bs_connected())); + connect(s, SIGNAL(error(int)), SLOT(bs_error(int))); + if(!proxy.user().isEmpty()) + s->setAuth(proxy.user(), proxy.pass()); + s->connectToHost(proxy.host(), proxy.port(), serverAddr.toString(), serverPort); + } + else if(proxy.type() == Proxy::Socks) + { + SocksClient *s = new SocksClient(this); + bs = s; + connect(s, SIGNAL(connected()), SLOT(bs_connected())); + connect(s, SIGNAL(error(int)), SLOT(bs_error(int))); + if(!proxy.user().isEmpty()) + s->setAuth(proxy.user(), proxy.pass()); + s->connectToHost(proxy.host(), proxy.port(), serverAddr.toString(), serverPort); + } + else + { + BSocket *s = new BSocket(this); + bs = s; + connect(s, SIGNAL(connected()), SLOT(bs_connected())); + connect(s, SIGNAL(error(int)), SLOT(bs_error(int))); + s->connectToHost(serverAddr.toString(), serverPort); + } + + connect(bs, SIGNAL(connectionClosed()), SLOT(bs_connectionClosed())); + connect(bs, SIGNAL(delayedCloseFinished()), SLOT(bs_delayedCloseFinished())); + connect(bs, SIGNAL(readyRead()), SLOT(bs_readyRead())); + connect(bs, SIGNAL(bytesWritten(int)), SLOT(bs_bytesWritten(int))); + } + + void do_close() + { + stopping = true; + + if(allocate && allocateStarted) + { + if(debugLevel >= TurnClient::DL_Info) + emit q->debugLine("Deallocating..."); + allocate->stop(); + } + else + { + delete allocate; + allocate = 0; + + // in udp mode, we don't own the pool + if(!udp) + delete pool; + pool = 0; + + if(udp) + sess.defer(q, "closed"); + else + do_transport_close(); + } + } + + void do_transport_close() + { + if(tls && tlsHandshaken) + { + tls->close(); + } + else + { + delete tls; + tls = 0; + + do_sock_close(); + } + } + + void do_sock_close() + { + bool waitForSignal = false; + if(bs->bytesToWrite() > 0) + waitForSignal = true; + + bs->close(); + if(!waitForSignal) + { + cleanup(); + sess.defer(q, "closed"); + } + } + + void after_connected() + { + // when retrying, pool will be non-null because we reuse it + if(!udp && !pool) + { + pool = new StunTransactionPool(StunTransaction::Tcp, this); + pool->setDebugLevel((StunTransactionPool::DebugLevel)debugLevel); + connect(pool, SIGNAL(outgoingMessage(const QByteArray &, const QHostAddress &, int)), SLOT(pool_outgoingMessage(const QByteArray &, const QHostAddress &, int))); + connect(pool, SIGNAL(needAuthParams()), SLOT(pool_needAuthParams())); + connect(pool, SIGNAL(debugLine(const QString &)), SLOT(pool_debugLine(const QString &))); + + pool->setLongTermAuthEnabled(true); + if(!user.isEmpty()) + { + pool->setUsername(user); + pool->setPassword(pass); + if(!realm.isEmpty()) + pool->setRealm(realm); + } + } + + allocate = new StunAllocate(pool); + connect(allocate, SIGNAL(started()), SLOT(allocate_started())); + connect(allocate, SIGNAL(stopped()), SLOT(allocate_stopped())); + connect(allocate, SIGNAL(error(XMPP::StunAllocate::Error)), SLOT(allocate_error(XMPP::StunAllocate::Error))); + connect(allocate, SIGNAL(permissionsChanged()), SLOT(allocate_permissionsChanged())); + connect(allocate, SIGNAL(channelsChanged()), SLOT(allocate_channelsChanged())); + connect(allocate, SIGNAL(debugLine(const QString &)), SLOT(allocate_debugLine(const QString &))); + + allocate->setClientSoftwareNameAndVersion(clientSoftware); + + allocateStarted = false; + if(debugLevel >= TurnClient::DL_Info) + emit q->debugLine("Allocating..."); + // only use addr association in udp mode + if(udp) + allocate->start(serverAddr, serverPort); + else + allocate->start(); + } + + void processStream(const QByteArray &in) + { + inStream += in; + + ObjectSessionWatcher watch(&sess); + while(1) + { + QByteArray packet; + + // try to extract ChannelData or a STUN message from + // the stream + packet = StunAllocate::readChannelData((const quint8 *)inStream.data(), inStream.size()); + if(packet.isNull()) + { + packet = StunMessage::readStun((const quint8 *)inStream.data(), inStream.size()); + if(packet.isNull()) + break; + } + + inStream = inStream.mid(packet.size()); + + // processDatagram may cause the session to be reset + // or the object to be deleted + processDatagram(packet); + if(!watch.isValid()) + break; + } + } + + void processDatagram(const QByteArray &buf) + { + bool notStun; + if(!pool->writeIncomingMessage(buf, ¬Stun)) + { + QByteArray data; + QHostAddress fromAddr; + int fromPort; + + data = processNonPoolPacket(buf, notStun, &fromAddr, &fromPort); + if(!data.isNull()) + processDataPacket(data, fromAddr, fromPort); + } + } + + QByteArray processNonPoolPacket(const QByteArray &buf, bool notStun, QHostAddress *addr, int *port) + { + if(notStun) + { + // not stun? maybe it is a data packet + QByteArray data = allocate->decode(buf, addr, port); + if(!data.isNull()) + { + if(debugLevel >= TurnClient::DL_Packet) + emit q->debugLine("Received ChannelData-based data packet"); + return data; + } + } + else + { + // packet might be stun not owned by pool. + // let's see + StunMessage message = StunMessage::fromBinary(buf); + if(!message.isNull()) + { + QByteArray data = allocate->decode(message, addr, port); + + if(!data.isNull()) + { + if(debugLevel >= TurnClient::DL_Packet) + emit q->debugLine("Received STUN-based data packet"); + return data; + } + else + { + if(debugLevel >= TurnClient::DL_Packet) + emit q->debugLine("Warning: server responded with an unexpected STUN packet, skipping."); + } + + return QByteArray(); + } + } + + if(debugLevel >= TurnClient::DL_Packet) + emit q->debugLine("Warning: server responded with what doesn't seem to be a STUN or data packet, skipping."); + return QByteArray(); + } + + void processDataPacket(const QByteArray &buf, const QHostAddress &addr, int port) + { + Packet p; + p.addr = addr; + p.port = port; + p.data = buf; + in += p; + + emit q->readyRead(); + } + + void writeOrQueue(const QByteArray &buf, const QHostAddress &addr, int port) + { + Q_ASSERT(allocateStarted); + + StunAllocate::Channel c(addr, port); + bool writeImmediately = false; + bool requireChannel = pendingChannels.contains(c) || desiredChannels.contains(c); + + QList<QHostAddress> actualPerms = allocate->permissions(); + if(actualPerms.contains(addr)) + { + if(requireChannel) + { + QList<StunAllocate::Channel> actualChannels = allocate->channels(); + if(actualChannels.contains(c)) + writeImmediately = true; + } + else + writeImmediately = true; + } + + if(writeImmediately) + { + write(buf, addr, port); + } + else + { + Packet p; + p.addr = addr; + p.port = port; + p.data = buf; + p.requireChannel = requireChannel; + outPending += p; + + ensurePermission(addr); + } + } + + void tryWriteQueued() + { + QList<QHostAddress> actualPerms = allocate->permissions(); + QList<StunAllocate::Channel> actualChannels = allocate->channels(); + for(int n = 0; n < outPending.count(); ++n) + { + const Packet &p = outPendingn; + if(actualPerms.contains(p.addr)) + { + StunAllocate::Channel c(p.addr, p.port); + if(!p.requireChannel || actualChannels.contains(c)) + { + Packet po = outPendingn; + outPending.removeAt(n); + --n; // adjust position + + write(po.data, po.addr, po.port); + } + } + } + } + + void tryChannelQueued() + { + if(!pendingChannels.isEmpty()) + { + QList<QHostAddress> actualPerms = allocate->permissions(); + QList<StunAllocate::Channel> list; + for(int n = 0; n < pendingChannels.count(); ++n) + { + if(actualPerms.contains(pendingChannelsn.address)) + { + list += pendingChannelsn; + pendingChannels.removeAt(n); + --n; // adjust position + } + } + + if(!list.isEmpty()) + ensureChannels(list); + } + } + + void write(const QByteArray &buf, const QHostAddress &addr, int port) + { + QByteArray packet = allocate->encode(buf, addr, port); + + if(debugLevel >= TurnClient::DL_Packet) + { + StunMessage msg = StunMessage::fromBinary(packet); + if(!msg.isNull()) + { + emit q->debugLine("STUN SEND"); + emit q->debugLine(StunTypes::print_packet_str(msg)); + } + else + emit q->debugLine("Sending ChannelData-based data packet"); + } + + writeItems += WriteItem(packet.size(), addr, port); + ++outPendingWrite; + if(udp) + { + emit q->outgoingDatagram(packet); + } + else + { + if(tls) + tls->write(packet); + else + bs->write(packet); + } + } + + void ensurePermission(const QHostAddress &addr) + { + if(!desiredPerms.contains(addr)) + { + if(debugLevel >= TurnClient::DL_Info) + emit q->debugLine(QString("Setting permission for peer address %1").arg(addr.toString())); + + desiredPerms += addr; + allocate->setPermissions(desiredPerms); + } + } + + // assumes we have perms for all input already + void ensureChannels(const QList<StunAllocate::Channel> &channels) + { + bool changed = false; + foreach(const StunAllocate::Channel &c, channels) + { + if(!desiredChannels.contains(c)) + { + if(debugLevel >= TurnClient::DL_Info) + emit q->debugLine(QString("Setting channel for peer address/port %1;%2").arg(c.address.toString()).arg(c.port)); + + desiredChannels += c; + changed = true; + } + } + + if(changed) + allocate->setChannels(desiredChannels); + } + + void addChannelPeer(const QHostAddress &addr, int port) + { + ensurePermission(addr); + + StunAllocate::Channel c(addr, port); + if(!pendingChannels.contains(c) && !desiredChannels.contains(c)) + { + pendingChannels += c; + + tryChannelQueued(); + } + } + + void udp_datagramsWritten(int count) + { + QList<Written> writtenDests; + + while(count > 0) + { + Q_ASSERT(!writeItems.isEmpty()); + WriteItem wi = writeItems.takeFirst(); + --count; + + if(wi.type == WriteItem::Data) + { + int at = -1; + for(int n = 0; n < writtenDests.count(); ++n) + { + if(writtenDestsn.addr == wi.addr && writtenDestsn.port == wi.port) + { + at = n; + break; + } + } + + if(at != -1) + { + ++writtenDestsat.count; + } + else + { + Written wr; + wr.addr = wi.addr; + wr.port = wi.port; + wr.count = 1; + writtenDests += wr; + } + } + } + + emitPacketsWritten(writtenDests); + } + + void emitPacketsWritten(const QList<Written> &writtenDests) + { + ObjectSessionWatcher watch(&sess); + foreach(const Written &wr, writtenDests) + { + emit q->packetsWritten(wr.count, wr.addr, wr.port); + if(!watch.isValid()) + return; + } + } + + // return true if we are retrying, false if we should error out + bool handleRetry() + { + ++retryCount; + if(retryCount < 3 && !stopping) + { + if(debugLevel >= TurnClient::DL_Info) + emit q->debugLine("retrying..."); + + // start completely over, but retain the same pool + // so the user isn't asked to auth again + + int tmp_retryCount = retryCount; + StunTransactionPool *tmp_pool = pool; + pool = 0; + + cleanup(); + + retryCount = tmp_retryCount; + pool = tmp_pool; + + do_connect(); + return true; + } + + return false; + } + +private slots: + void bs_connected() + { + ObjectSessionWatcher watch(&sess); + emit q->connected(); + if(!watch.isValid()) + return; + + if(mode == TurnClient::TlsMode) + { + tls = new QCA::TLS(this); + connect(tls, SIGNAL(handshaken()), SLOT(tls_handshaken())); + connect(tls, SIGNAL(readyRead()), SLOT(tls_readyRead())); + connect(tls, SIGNAL(readyReadOutgoing()), SLOT(tls_readyReadOutgoing())); + connect(tls, SIGNAL(error()), SLOT(tls_error())); + tlsHandshaken = false; + if(debugLevel >= TurnClient::DL_Info) + emit q->debugLine("TLS handshaking..."); + tls->startClient(); + } + else + after_connected(); + } + + void bs_connectionClosed() + { + cleanup(); + errorString = "Server unexpectedly disconnected."; + emit q->error(TurnClient::ErrorStream); + } + + void bs_delayedCloseFinished() + { + cleanup(); + emit q->closed(); + } + + void bs_readyRead() + { + QByteArray buf = bs->read(); + + if(tls) + tls->writeIncoming(buf); + else + processStream(buf); + } + + void bs_bytesWritten(int written) + { + if(tls) + { + // convertBytesWritten() is unsafe to call unless + // the TLS handshake is completed + if(!tlsHandshaken) + return; + + written = tls->convertBytesWritten(written); + } + + writtenBytes += written; + + QList<Written> writtenDests; + + while(writtenBytes > 0) + { + Q_ASSERT(!writeItems.isEmpty()); + if(writtenBytes < writeItems.first().size) + break; + + WriteItem wi = writeItems.takeFirst(); + writtenBytes -= wi.size; + + if(wi.type == WriteItem::Data) + { + int at = -1; + for(int n = 0; n < writtenDests.count(); ++n) + { + if(writtenDestsn.addr == wi.addr && writtenDestsn.port == wi.port) + { + at = n; + break; + } + } + + if(at != -1) + { + ++writtenDestsat.count; + } + else + { + Written wr; + wr.addr = wi.addr; + wr.port = wi.port; + wr.count = 1; + writtenDests += wr; + } + } + } + + emitPacketsWritten(writtenDests); + } + + void bs_error(int e) + { + TurnClient::Error te; + if(qobject_cast<HttpConnect*>(bs)) + { + if(e == HttpConnect::ErrConnectionRefused) + te = TurnClient::ErrorConnect; + else if(e == HttpConnect::ErrHostNotFound) + te = TurnClient::ErrorHostNotFound; + else if(e == HttpConnect::ErrProxyConnect) + te = TurnClient::ErrorProxyConnect; + else if(e == HttpConnect::ErrProxyNeg) + te = TurnClient::ErrorProxyNeg; + else if(e == HttpConnect::ErrProxyAuth) + te = TurnClient::ErrorProxyAuth; + else + te = TurnClient::ErrorStream; + } + else if(qobject_cast<SocksClient*>(bs)) + { + if(e == SocksClient::ErrConnectionRefused) + te = TurnClient::ErrorConnect; + else if(e == SocksClient::ErrHostNotFound) + te = TurnClient::ErrorHostNotFound; + else if(e == SocksClient::ErrProxyConnect) + te = TurnClient::ErrorProxyConnect; + else if(e == SocksClient::ErrProxyNeg) + te = TurnClient::ErrorProxyNeg; + else if(e == SocksClient::ErrProxyAuth) + te = TurnClient::ErrorProxyAuth; + else + te = TurnClient::ErrorStream; + } + else + { + if(e == BSocket::ErrConnectionRefused) + te = TurnClient::ErrorConnect; + else if(e == BSocket::ErrHostNotFound) + te = TurnClient::ErrorHostNotFound; + else + te = TurnClient::ErrorStream; + } + + cleanup(); + errorString = "Transport error."; + emit q->error(te); + } + + void tls_handshaken() + { + tlsHandshaken = true; + + ObjectSessionWatcher watch(&sess); + emit q->tlsHandshaken(); + if(!watch.isValid()) + return; + + tls->continueAfterStep(); + after_connected(); + } + + void tls_readyRead() + { + processStream(tls->read()); + } + + void tls_readyReadOutgoing() + { + bs->write(tls->readOutgoing()); + } + + void tls_closed() + { + delete tls; + tls = 0; + + do_sock_close(); + } + + void tls_error() + { + cleanup(); + errorString = "TLS error."; + emit q->error(TurnClient::ErrorTls); + } + + void pool_outgoingMessage(const QByteArray &packet, const QHostAddress &toAddress, int toPort) + { + // we aren't using IP-associated transactions + Q_UNUSED(toAddress); + Q_UNUSED(toPort); + + writeItems += WriteItem(packet.size()); + + if(tls) + tls->write(packet); + else + bs->write(packet); + } + + void pool_needAuthParams() + { + emit q->needAuthParams(); + } + + void pool_debugLine(const QString &line) + { + emit q->debugLine(line); + } + + void allocate_started() + { + allocateStarted = true; + if(debugLevel >= TurnClient::DL_Info) + emit q->debugLine("Allocate started"); + + emit q->activated(); + } + + void allocate_stopped() + { + delete allocate; + allocate = 0; + + // in udp mode, we don't own the pool + if(!udp) + delete pool; + pool = 0; + + if(udp) + emit q->closed(); + else + do_transport_close(); + } + + void allocate_error(XMPP::StunAllocate::Error e) + { + QString str = allocate->errorString(); + + TurnClient::Error te; + if(e == StunAllocate::ErrorAuth) + te = TurnClient::ErrorAuth; + else if(e == StunAllocate::ErrorRejected) + te = TurnClient::ErrorRejected; + else if(e == StunAllocate::ErrorProtocol) + te = TurnClient::ErrorProtocol; + else if(e == StunAllocate::ErrorCapacity) + te = TurnClient::ErrorCapacity; + else if(e == StunAllocate::ErrorMismatch) + { + if(!udp && handleRetry()) + return; + + te = TurnClient::ErrorMismatch; + } + else + te = TurnClient::ErrorGeneric; + + cleanup(); + errorString = str; + emit q->error(te); + } + + void allocate_permissionsChanged() + { + if(debugLevel >= TurnClient::DL_Info) + emit q->debugLine("PermissionsChanged"); + + tryChannelQueued(); + tryWriteQueued(); + } + + void allocate_channelsChanged() + { + if(debugLevel >= TurnClient::DL_Info) + emit q->debugLine("ChannelsChanged"); + + tryWriteQueued(); + } + + void allocate_debugLine(const QString &line) + { + emit q->debugLine(line); + } +}; + +TurnClient::TurnClient(QObject *parent) : + QObject(parent) +{ + d = new Private(this); +} + +TurnClient::~TurnClient() +{ + delete d; +} + +void TurnClient::setProxy(const Proxy &proxy) +{ + d->proxy = proxy; +} + +void TurnClient::setClientSoftwareNameAndVersion(const QString &str) +{ + d->clientSoftware = str; +} + +void TurnClient::connectToHost(StunTransactionPool *pool, const QHostAddress &addr, int port) +{ + d->serverAddr = addr; + d->serverPort = port; + d->udp = true; + d->pool = pool; + d->in.clear(); + d->do_connect(); +} + +void TurnClient::connectToHost(const QHostAddress &addr, int port, Mode mode) +{ + d->serverAddr = addr; + d->serverPort = port; + d->udp = false; + d->mode = mode; + d->in.clear(); + d->do_connect(); +} + +QByteArray TurnClient::processIncomingDatagram(const QByteArray &buf, bool notStun, QHostAddress *addr, int *port) +{ + return d->processNonPoolPacket(buf, notStun, addr, port); +} + +void TurnClient::outgoingDatagramsWritten(int count) +{ + d->udp_datagramsWritten(count); +} + +QString TurnClient::realm() const +{ + if(d->pool) + return d->pool->realm(); + else + return d->realm; +} + +void TurnClient::setUsername(const QString &username) +{ + d->user = username; + if(d->pool) + d->pool->setUsername(d->user); +} + +void TurnClient::setPassword(const QCA::SecureArray &password) +{ + d->pass = password; + if(d->pool) + d->pool->setPassword(d->pass); +} + +void TurnClient::setRealm(const QString &realm) +{ + d->realm = realm; + if(d->pool) + d->pool->setRealm(d->realm); +} + +void TurnClient::continueAfterParams() +{ + Q_ASSERT(d->pool); + d->pool->continueAfterParams(); +} + +void TurnClient::close() +{ + d->do_close(); +} + +StunAllocate *TurnClient::stunAllocate() +{ + return d->allocate; +} + +void TurnClient::addChannelPeer(const QHostAddress &addr, int port) +{ + d->addChannelPeer(addr, port); +} + +int TurnClient::packetsToRead() const +{ + return d->in.count(); +} + +int TurnClient::packetsToWrite() const +{ + return d->outPending.count() + d->outPendingWrite; +} + +QByteArray TurnClient::read(QHostAddress *addr, int *port) +{ + if(!d->in.isEmpty()) + { + Private::Packet p = d->in.takeFirst(); + *addr = p.addr; + *port = p.port; + return p.data; + } + else + return QByteArray(); +} + +void TurnClient::write(const QByteArray &buf, const QHostAddress &addr, int port) +{ + d->writeOrQueue(buf, addr, port); +} + +QString TurnClient::errorString() const +{ + return d->errorString; +} + +void TurnClient::setDebugLevel(DebugLevel level) +{ + d->debugLevel = level; + if(d->pool) + d->pool->setDebugLevel((StunTransactionPool::DebugLevel)level); +} + +} + +#include "turnclient.moc"
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/turnclient.h
Added
@@ -0,0 +1,194 @@ +/* + * Copyright (C) 2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef TURNCLIENT_H +#define TURNCLIENT_H + +#include <QObject> +#include <QByteArray> +#include <QString> +#include <QHostAddress> + +namespace QCA { + class SecureArray; +} + +namespace XMPP { + +class StunTransactionPool; +class StunAllocate; + +class TurnClient : public QObject +{ + Q_OBJECT + +public: + enum Error + { + ErrorGeneric, + ErrorHostNotFound, + ErrorConnect, + + // stream error or stream unexpectedly disconnected by peer + ErrorStream, + + ErrorProxyConnect, + ErrorProxyNeg, + ErrorProxyAuth, + ErrorTls, + ErrorAuth, + ErrorRejected, + ErrorProtocol, + ErrorCapacity, + + // according to the TURN spec, a client should try three times + // to correct a mismatch error before giving up. this class + // will perform the retries internally, and ErrorMismatch is + // only emitted when it has given up. note that if this + // happens, the TURN spec says you should not connect to the + // TURN server again for at least 2 minutes. + // note: in UDP mode, this class does not perform retries and + // will emit this error immediately. + ErrorMismatch + }; + + enum Mode + { + PlainMode, + TlsMode + }; + + enum DebugLevel + { + DL_None, + DL_Info, + DL_Packet + }; + + // adapted from XMPP::AdvancedConnector + class Proxy + { + public: + enum + { + None, + HttpConnect, + Socks + }; + + Proxy(); + ~Proxy(); + + int type() const; + QString host() const; + quint16 port() const; + QString user() const; + QString pass() const; + + void setHttpConnect(const QString &host, quint16 port); + void setSocks(const QString &host, quint16 port); + void setUserPass(const QString &user, const QString &pass); + + private: + int t; + QString v_host; + quint16 v_port; + QString v_user, v_pass; + }; + + TurnClient(QObject *parent = 0); + ~TurnClient(); + + void setProxy(const Proxy &proxy); + void setClientSoftwareNameAndVersion(const QString &str); + + // for UDP. does not take ownership of the pool. stun transaction + // I/O occurs through the pool. transfer of data packets occurs + // via processIncomingDatagram(), outgoingDatagram(), and + // outgoingDatagramsWritten(). authentication happens through the + // pool and not through this class. the turn addr/port is optional, + // and used only for addr association with the pool + void connectToHost(StunTransactionPool *pool, const QHostAddress &addr = QHostAddress(), int port = -1); + + // for TCP and TCP-TLS + void connectToHost(const QHostAddress &addr, int port, Mode mode = PlainMode); + + // for UDP, use this function to process incoming packets instead of + // read(). + QByteArray processIncomingDatagram(const QByteArray &buf, bool notStun, QHostAddress *addr, int *port); + + // call after writing datagrams from outgoingDatagram. not DOR-DS safe + void outgoingDatagramsWritten(int count); + + QString realm() const; + void setUsername(const QString &username); + void setPassword(const QCA::SecureArray &password); + void setRealm(const QString &realm); + void continueAfterParams(); + + void close(); + + StunAllocate *stunAllocate(); + + void addChannelPeer(const QHostAddress &addr, int port); + + int packetsToRead() const; + int packetsToWrite() const; + + // TCP mode only + QByteArray read(QHostAddress *addr, int *port); + + // for UDP, this call may emit outgoingDatagram() immediately (not + // DOR-DS safe) + void write(const QByteArray &buf, const QHostAddress &addr, int port); + + QString errorString() const; + + void setDebugLevel(DebugLevel level); // default DL_None + +signals: + void connected(); // tcp connected + void tlsHandshaken(); + void closed(); + void needAuthParams(); + void retrying(); // mismatch error received, starting all over + void activated(); // ready for read/write + + // TCP mode only + void readyRead(); + + void packetsWritten(int count, const QHostAddress &addr, int port); + void error(XMPP::TurnClient::Error e); + + // data packets to be sent to the TURN server, UDP mode only + void outgoingDatagram(const QByteArray &buf); + + // not DOR-SS/DS safe + void debugLine(const QString &line); + +private: + class Private; + friend class Private; + Private *d; +}; + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/udpportreserver.cpp
Added
@@ -0,0 +1,435 @@ +/* + * Copyright (C) 2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "udpportreserver.h" + +#include <QUdpSocket> + +namespace XMPP { + +class UdpPortReserver::Private : public QObject +{ + Q_OBJECT + +public: + class Item + { + public: + int port; // port to reserve + bool lent; + + // list of sockets for this port, one socket per address. + // note that we may have sockets bound for addresses + // we no longer care about, if we are currently lending + // them out + QList<QUdpSocket*> sockList; + + // keep track of which addresses we lent out + QList<QHostAddress> lentAddrs; + + Item() : + port(-1), + lent(false) + { + } + + bool haveAddress(const QHostAddress &addr) const + { + foreach(const QUdpSocket *sock, sockList) + { + if(sock->localAddress() == addr) + return true; + } + + return false; + } + }; + + UdpPortReserver *q; + QList<QHostAddress> addrs; + QList<int> ports; // sorted + QList<Item> items; // in order sorted by port + + Private(UdpPortReserver *_q) : + QObject(_q), + q(_q) + { + } + + ~Private() + { + bool lendingAny = false; + foreach(const Item &i, items) + { + if(i.lent) + { + lendingAny = true; + break; + } + } + + Q_ASSERT(!lendingAny); + + foreach(const Item &i, items) + { + foreach(QUdpSocket *sock, i.sockList) + sock->deleteLater(); + } + } + + void updateAddresses(const QList<QHostAddress> &newAddrs) + { + addrs = newAddrs; + + tryBind(); + tryCleanup(); + } + + void updatePorts(const QList<int> &newPorts) + { + QList<int> added; + foreach(int x, newPorts) + { + bool found = false; + foreach(const Item &i, items) + { + if(i.port == x) + { + found = true; + break; + } + } + + if(!found) + added += x; + } + + ports = newPorts; + + // keep ports in sorted order + qSort(ports); + + foreach(int x, added) + { + int insert_before = items.count(); + for(int n = 0; n < items.count(); ++n) + { + if(x < itemsn.port) + { + insert_before = n; + break; + } + } + + Item i; + i.port = x; + items.insert(insert_before, i); + } + + tryBind(); + tryCleanup(); + } + + bool reservedAll() const + { + bool ok = true; + foreach(const Item &i, items) + { + // skip ports we don't care about + if(!ports.contains(i.port)) + continue; + + if(!isReserved(i)) + { + ok = false; + break; + } + } + + return ok; + } + + QList<QUdpSocket*> borrowSockets(int portCount, QObject *parent) + { + Q_ASSERT(portCount > 0); + + QList<QUdpSocket*> out; + + if(portCount > 1) + { + // first try to see if we can find something all in a + // row, starting with best alignment to worst + for(int align = portCount; align >= 2; align /= 2) + { + int at = findConsecutive(portCount, align); + if(at != -1) + { + for(int n = 0; n < portCount; ++n) + out += lendItem(&itemsat + n, parent); + + break; + } + } + + if(out.isEmpty()) + { + // otherwise, try splitting them up into + // smaller consecutive chunks + int chunks2; + chunks0 = portCount / 2 + (portCount % 2); + chunks1 = portCount / 2; + for(int n = 0; n < 2; ++n) + out += borrowSockets(chunksn, parent); + } + } + else + { + // take the next available port + int at = findConsecutive(1, 1); + if(at != -1) + out += lendItem(&itemsat, parent); + } + + return out; + } + + void returnSockets(const QList<QUdpSocket*> &sockList) + { + foreach(QUdpSocket *sock, sockList) + { + int at = -1; + for(int n = 0; n < items.count(); ++n) + { + if(itemsn.sockList.contains(sock)) + { + at = n; + break; + } + } + + Q_ASSERT(at != -1); + + Item &i = itemsat; + + QHostAddress a = sock->localAddress(); + + Q_ASSERT(i.lent); + Q_ASSERT(i.lentAddrs.contains(a)); + + sock->setParent(q); + connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); + + i.lentAddrs.removeAll(a); + if(i.lentAddrs.isEmpty()) + i.lent = false; + } + + tryCleanup(); + } + +private slots: + void sock_readyRead() + { + QUdpSocket *sock = (QUdpSocket *)sender(); + + // eat all packets + while(sock->hasPendingDatagrams()) + sock->readDatagram(0, 0); + } + +private: + void tryBind() + { + for(int n = 0; n < items.count(); ++n) + { + Item &i = itemsn; + + // skip ports we don't care about + if(!ports.contains(i.port)) + continue; + + QList<QHostAddress> neededAddrs; + foreach(const QHostAddress &a, addrs) + { + if(!i.haveAddress(a)) + neededAddrs += a; + } + + foreach(const QHostAddress &a, neededAddrs) + { + QUdpSocket *sock = new QUdpSocket(q); + + if(!sock->bind(a, i.port)) + { + delete sock; + continue; + } + + connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); + + i.sockList += sock; + } + } + } + + void tryCleanup() + { + for(int n = 0; n < items.count(); ++n) + { + Item &i = itemsn; + + // don't care about this port anymore? + if(!i.lent && !ports.contains(i.port)) + { + foreach(QUdpSocket *sock, i.sockList) + sock->deleteLater(); + + items.removeAt(n); + --n; // adjust position + continue; + } + + // any addresses we don't care about? + for(int k = 0; k < i.sockList.count(); ++k) + { + QUdpSocket *sock = i.sockListk; + + QHostAddress a = sock->localAddress(); + + if(!addrs.contains(a) && !i.lentAddrs.contains(a)) + { + sock->deleteLater(); + i.sockList.removeAt(k); + --k; // adjust position + continue; + } + } + } + } + + bool isReserved(const Item &i) const + { + // must have desired addrs to consider a port reserved + if(addrs.isEmpty()) + return false; + + foreach(const QHostAddress &a, addrs) + { + if(!i.haveAddress(a)) + return false; + } + + return true; + } + + bool isConsecutive(int at, int count) const + { + if(at + count > items.count()) + return false; + + for(int n = 0; n < count; ++n) + { + const Item &i = itemsat + n; + + if(i.lent || !isReserved(i)) + return false; + + if(n > 0 && (i.port != itemsat + n - 1.port + 1)) + return false; + } + + return true; + } + + int findConsecutive(int count, int align) const + { + for(int n = 0; n < items.count(); n += align) + { + if(isConsecutive(n, count)) + return n; + } + + return -1; + } + + QList<QUdpSocket*> lendItem(Item *i, QObject *parent) + { + QList<QUdpSocket*> out; + + i->lent = true; + foreach(QUdpSocket *sock, i->sockList) + { + i->lentAddrs += sock->localAddress(); + sock->disconnect(this); + sock->setParent(parent); + out += sock; + } + + return out; + } +}; + +UdpPortReserver::UdpPortReserver(QObject *parent) : + QObject(parent) +{ + d = new Private(this); +} + +UdpPortReserver::~UdpPortReserver() +{ + delete d; +} + +void UdpPortReserver::setAddresses(const QList<QHostAddress> &addrs) +{ + d->updateAddresses(addrs); +} + +void UdpPortReserver::setPorts(int start, int len) +{ + QList<int> ports; + for(int n = 0; n < len; ++n) + ports += start + n; + setPorts(ports); +} + +void UdpPortReserver::setPorts(const QList<int> &ports) +{ + d->updatePorts(ports); +} + +bool UdpPortReserver::reservedAll() const +{ + return d->reservedAll(); +} + +QList<QUdpSocket*> UdpPortReserver::borrowSockets(int portCount, QObject *parent) +{ + return d->borrowSockets(portCount, parent); +} + +void UdpPortReserver::returnSockets(const QList<QUdpSocket*> &sockList) +{ + d->returnSockets(sockList); +} + +} + +#include "udpportreserver.moc"
View file
libjreen-1.1.0.tar.bz2/3rdparty/icesupport/udpportreserver.h
Added
@@ -0,0 +1,74 @@ +/* + * Copyright (C) 2010 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef UDPPORTRESERVER_H +#define UDPPORTRESERVER_H + +#include <QObject> +#include <QList> + +class QHostAddress; +class QUdpSocket; + +namespace XMPP { + +// call both setAddresses() and setPorts() at least once for socket +// reservations to occur. at any time you can update the list of addresses +// (interfaces) and ports to reserve. note that the port must be available +// on all addresses in order for it to get reserved. +// note: you must return all sockets back to this class before destructing +class UdpPortReserver : public QObject +{ + Q_OBJECT + +public: + UdpPortReserver(QObject *parent = 0); + ~UdpPortReserver(); + + void setAddresses(const QList<QHostAddress> &addrs); + void setPorts(int start, int len); + void setPorts(const QList<int> &ports); + + // return true if all ports got reserved, false if only some + // or none got reserved + bool reservedAll() const; + + // may return less than asked for, if we had less reserved ports + // left. some attempt is made to return aligned or consecutive port + // values, but this is just a best effort and not a guarantee. if + // not all ports were able to be reserved earlier, then this call + // may attempt to reserve those ports again. the sockets in the + // returned list are ordered by port (in ascending order) and then + // by address (in the order provided). since all addresses must be + // able to bind to a port for it to be considered reserved, this + // function always returns a list with a size that is a multiple of + // the number of addresses. + QList<QUdpSocket*> borrowSockets(int portCount, QObject *parent = 0); + + void returnSockets(const QList<QUdpSocket*> &sockList); + +private: + class Private; + Private *d; +}; + +} + +#endif
View file
libjreen-1.0.3.tar.bz2/CMakeLists.txt -> libjreen-1.1.0.tar.bz2/CMakeLists.txt
Changed
@@ -4,13 +4,13 @@ LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(CMAKE_JREEN_VERSION_MAJOR 1 CACHE INT "Major Jreen version number" FORCE) -set(CMAKE_JREEN_VERSION_MINOR 0 CACHE INT "Minor Jreen version number" FORCE) -set(CMAKE_JREEN_VERSION_PATCH 3 CACHE INT "Release Jreen version number" FORCE) +set(CMAKE_JREEN_VERSION_MINOR 1 CACHE INT "Minor Jreen version number" FORCE) +set(CMAKE_JREEN_VERSION_PATCH 0 CACHE INT "Release Jreen version number" FORCE) set(CMAKE_JREEN_VERSION_STRING "${CMAKE_JREEN_VERSION_MAJOR}.${CMAKE_JREEN_VERSION_MINOR}.${CMAKE_JREEN_VERSION_PATCH}" CACHE STRING "Jreen version string" FORCE) # Search for source and headers in source directory (non-recursive) -FILE(GLOB SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") -FILE(GLOB HDR "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h") +FILE(GLOB_RECURSE SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +FILE(GLOB_RECURSE HDR "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h") # Require QT 4.6 SET(QT_MIN_VERSION "4.6.0") @@ -20,9 +20,29 @@ INCLUDE(${QT_USE_FILE}) INCLUDE(jreenMacros) FIND_PACKAGE(QCA2 REQUIRED) -#FIND_PACKAGE(ZLIB REQUIRED) -FIND_PACKAGE(LibIDN) +if( JREEN_BUILD_INTERNAL ) + add_definitions( "-DJ_BUILD_INTERNAL" ) +endif() +FIND_PACKAGE(PkgConfig) + +#pkg_search_module(NICE nice) +#if(NOT NICE_FOUND) +# message(STATUS "Could not find nice library.") +#else(NOT NICE_FOUND) +# message(STATUS "Nice library is found.") +# include_directories(${NICE_INCLUDE_DIRS}) +# ADD_DEFINITIONS("-DJREEN_HAVE_NICE=1") +#endif(NOT NICE_FOUND) + +pkg_search_module(SPEEX speex) +if(NOT SPEEX_FOUND) + message(STATUS "Could not find speex library.") +else(NOT SPEEX_FOUND) + message(STATUS "Speex library is found.") + include_directories(${SPEEX_INCLUDE_DIRS}) + ADD_DEFINITIONS("-DJREEN_HAVE_SPEEX=1") +endif(NOT SPEEX_FOUND) # FindZLIB is broken on Ubuntu, so find the library using pkg-config if(LINUX) @@ -42,6 +62,8 @@ if(NOT ZLIB_LIBRARIES) message(SEND_ERROR "Could not find zlib library.") endif(NOT ZLIB_LIBRARIES) + + else() find_package(ZLIB REQUIRED) endif() @@ -57,15 +79,23 @@ ${QCA2_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ) -IF(LIBIDN_FOUND) - INCLUDE_DIRECTORIES(${LIBIDN_INCLUDE_DIR}) - ADD_DEFINITIONS("-DHAVE_IDN=1") -ENDIF(LIBIDN_FOUND) LIST(APPEND SRC ${3RD_PARTY_SRC_C}) LIST(APPEND SRC ${3RD_PARTY_SRC}) LIST(APPEND HDR ${3RD_PARTY_HDR}) +# Ice support +option(JREEN_USE_IRISICE "Use ICE from IRIS" OFF) +if (JREEN_USE_IRISICE) + file(GLOB_RECURSE ICESUPPORT_SRC "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/icesupport/*.cpp") + file(GLOB_RECURSE ICESUPPORT_SRC_C "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/icesupport/*.c") + file(GLOB_RECURSE ICESUPPORT_HDR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/icesupport/*.h") + list(APPEND SRC ${ICESUPPORT_SRC}) + list(APPEND SRC ${ICESUPPORT_SRC_C}) + list(APPEND HDR ${ICESUPPORT_HDR}) + add_definitions("-DHAVE_IRISICE") +endif() + option(JREEN_USE_SIMPLESASL "Use SimpleSASL" ON) if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/simplesasl") set(JREEN_USE_SIMPLESASL OFF) @@ -159,9 +189,12 @@ IF(WIN32) LIST(APPEND EXTRA_LIBS ws2_32) ENDIF() -IF(LIBIDN_FOUND) - LIST(APPEND EXTRA_LIBS ${LIBIDN_LIBRARIES}) -ENDIF(LIBIDN_FOUND) +#IF(NICE_FOUND) +# LIST(APPEND EXTRA_LIBS ${NICE_LIBRARIES}) +#ENDIF(NICE_FOUND) +IF(SPEEX_FOUND) + LIST(APPEND EXTRA_LIBS ${SPEEX_LIBRARIES}) +ENDIF(SPEEX_FOUND) # Link with Qt #IF(SYMBIAN)
View file
libjreen-1.0.3.tar.bz2/ChangeLog -> libjreen-1.1.0.tar.bz2/ChangeLog
Changed
@@ -1,8 +1,30 @@ -Version 1.0.3 +Version 1.1.0 + * Added PGP payloads + * Added support for Message Forwarding + * Added MetaContacts support + * Added experimental Jingle support + * Fixed authorization with SCRAM-SHA1 + * Fixed sending of IQ's on connect + +Version 1.0.6: + * Fixed parsing of PubSub payload + * Fixed serializing of PubSub payload + +Version 1.0.5: + * Fixed parsing of message's thread attribute + +Version 1.0.4: + * Added support for in-band registration + * Added ability to force/deny compression/encryption + * Added CAPTCHA support + * Fixed IQ requests to yourself + * Fixed handling of messages' types in MessageSession + +Version 1.0.3: * Added Logger implementation * Fixed QJDns initialization issue -Version 1.0.2 +Version 1.0.2: * Added support for ProxyFactory * Added immunity to invalid stanzas * Added localization support for incoming stanzas
View file
libjreen-1.0.3.tar.bz2/cmake/jreenMacros.cmake -> libjreen-1.1.0.tar.bz2/cmake/jreenMacros.cmake
Changed
@@ -32,6 +32,8 @@ SET(_header ${_abs_PATH}/${_basename}.cpp) FILE(READ ${_header} _contents) STRING(REGEX MATCHALL "# *include +\">moc_^ +\\.cpp\">" _match "${_contents}") + STRING(REGEX MATCHALL "# *include +^ +\\.moc\">" _match2 "${_contents}") + STRING(REGEX MATCHALL "Q_OBJECT" _match3 "${_contents}") IF(_match) SET(_HAS_MOC true) FOREACH (_current_MOC_INC ${_match}) @@ -41,6 +43,14 @@ MACRO_ADD_FILE_DEPENDENCIES(${_abs_FILE} ${_moc}) ENDFOREACH (_current_MOC_INC) ENDIF() + IF(_match2) + FOREACH (_current_MOC_INC ${_match2}) + STRING(REGEX MATCH "^ <\"+\\.moc" _current_MOC "${_current_MOC_INC}") + SET(_moc ${CMAKE_CURRENT_BINARY_DIR}/${_current_MOC}) + QT4_CREATE_MOC_COMMAND(${_header} ${_moc} "${_moc_INCS}" "") + MACRO_ADD_FILE_DEPENDENCIES(${_header} ${_moc}) + ENDFOREACH (_current_MOC_INC) + ENDIF() ENDIF() IF(NOT _HAS_MOC) FILE(READ ${_abs_FILE} _contents)
View file
libjreen-1.1.0.tar.bz2/deffered
Added
+(directory)
View file
libjreen-1.1.0.tar.bz2/deffered/gui
Added
+(directory)
View file
libjreen-1.1.0.tar.bz2/deffered/gui/jidedit.cpp
Changed
(renamed from src/gui/jidedit.cpp)
View file
libjreen-1.1.0.tar.bz2/deffered/gui/jidedit.h
Changed
(renamed from src/gui/jidedit.h)
View file
libjreen-1.1.0.tar.bz2/deffered/gui/jidedit_p.h
Changed
(renamed from src/gui/jidedit_p.h)
View file
libjreen-1.1.0.tar.bz2/deffered/gui/xmlconsole.cpp
Changed
(renamed from src/gui/xmlconsole.cpp)
View file
libjreen-1.1.0.tar.bz2/deffered/gui/xmlconsole.h
Changed
(renamed from src/gui/xmlconsole.h)
View file
libjreen-1.1.0.tar.bz2/deffered/gui/xmlconsole.ui
Changed
(renamed from src/gui/xmlconsole.ui)
View file
libjreen-1.0.3.tar.bz2/src/abstractroster.cpp -> libjreen-1.1.0.tar.bz2/src/abstractroster.cpp
Changed
@@ -33,6 +33,8 @@ #include "logger.h" #include "util.h" +#define NS_ROSTER QLatin1String("jabber:iq:roster") + namespace Jreen { @@ -55,13 +57,13 @@ QStringList AbstractRosterQueryFactory::features() const { - return QStringList(QLatin1String("jabber:iq:roster")); + return QStringList(NS_ROSTER); } bool AbstractRosterQueryFactory::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) { Q_UNUSED(attributes); - return name == QLatin1String("query") && uri == QLatin1String("jabber:iq:roster"); + return name == QLatin1String("query") && uri == NS_ROSTER; } void AbstractRosterQueryFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) @@ -119,7 +121,7 @@ if (!query) return; writer->writeStartElement(QLatin1String("query")); - writer->writeDefaultNamespace(QLatin1String("jabber:iq:roster")); + writer->writeDefaultNamespace(NS_ROSTER); if (query->items().isEmpty()) writer->writeAttribute(QLatin1String("ver"), query->ver()); foreach (const RosterItem::Ptr &item, query->items()) { @@ -141,12 +143,8 @@ return Payload::Ptr(new AbstractRosterQuery(m_items, m_ver)); } -static const QStringList roster_subscriptions = QStringList() -<< QLatin1String("from") << QLatin1String("to") -<< QLatin1String("both") << QLatin1String("remove"); - RosterItem::RosterItem(const QString &jid, const QString &name, - const QStringList &groups, SubscriptionType s10n) + const QStringList &groups, SubscriptionType s10n) : d_ptr(new RosterItemPrivate) { Q_D(RosterItem);
View file
libjreen-1.0.3.tar.bz2/src/abstractroster.h -> libjreen-1.1.0.tar.bz2/src/abstractroster.h
Changed
@@ -58,7 +58,7 @@ class RosterItemPrivate; class AbstractRosterQuery; -class ItemFactory : public XmlStreamFactory<RosterItem> +class JREEN_AUTOTEST_EXPORT ItemFactory : public XmlStreamFactory<RosterItem> { public: }; @@ -137,7 +137,7 @@ virtual void onLoaded(const QList<QSharedPointer<RosterItem> > &items); QScopedPointer<AbstractRosterPrivate> d_ptr; friend class AbstractRosterQuery; - friend class AbstractRosterQueryFactory; + friend class JREEN_AUTOTEST_EXPORT AbstractRosterQueryFactory; friend class RosterItem; };
View file
libjreen-1.0.3.tar.bz2/src/abstractroster_p.h -> libjreen-1.1.0.tar.bz2/src/abstractroster_p.h
Changed
@@ -68,7 +68,7 @@ QString m_ver; }; -class AbstractRosterQueryFactory : public PayloadFactory<AbstractRosterQuery> +class JREEN_AUTOTEST_EXPORT AbstractRosterQueryFactory : public PayloadFactory<AbstractRosterQuery> { public: AbstractRosterQueryFactory(AbstractRoster *roster);
View file
libjreen-1.0.3.tar.bz2/src/activityfactory_p.h -> libjreen-1.1.0.tar.bz2/src/activityfactory_p.h
Changed
@@ -32,7 +32,7 @@ namespace Jreen { -class ActivityFactory : public PayloadFactory<Activity> +class JREEN_AUTOTEST_EXPORT ActivityFactory : public PayloadFactory<Activity> { public: ActivityFactory();
View file
libjreen-1.0.3.tar.bz2/src/bindfeature.cpp -> libjreen-1.1.0.tar.bz2/src/bindfeature.cpp
Changed
@@ -49,7 +49,7 @@ bool m_bind; }; -class BindQueryFactory : public PayloadFactory<BindQuery> +class JREEN_AUTOTEST_EXPORT BindQueryFactory : public PayloadFactory<BindQuery> { public: BindQueryFactory() : m_bind(true), m_depth(0), m_state(AtStart) {}
View file
libjreen-1.1.0.tar.bz2/src/bitsofbinary.cpp
Added
@@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "bitsofbinary.h" +#include <QCryptographicHash> +#include <QUrl> + +namespace Jreen +{ + +class BitsOfBinaryPrivate +{ +public: + mutable QUrl cid; + qint64 maximumAge; + QByteArray data; + QString type; +}; + +BitsOfBinary::BitsOfBinary(const QByteArray &data, qint64 age) : d_ptr(new BitsOfBinaryPrivate) +{ + Q_D(BitsOfBinary); + d->maximumAge = age; + d->data = data; +} + +BitsOfBinary::BitsOfBinary(const QUrl &cid) +{ + Q_D(BitsOfBinary); + d->maximumAge = -1; + d->cid = cid; +} + +BitsOfBinary::~BitsOfBinary() +{ +} + +QUrl BitsOfBinary::cid() const +{ + Q_D(const BitsOfBinary); + if (!d->data.isEmpty() && d->cid.isEmpty()) { + QString cid = QLatin1String("sha1+"); + QCryptographicHash hash(QCryptographicHash::Sha1); + hash.addData(d->data); + cid += hash.result().toHex(); + cid += QLatin1String("@bob.xmpp.org"); + d->cid = QUrl(cid); + } + return d->cid; +} + +void BitsOfBinary::setCid(const QUrl &cid) +{ + d_func()->cid = cid; +} + +qint64 BitsOfBinary::maximumAge() const +{ + return d_func()->maximumAge; +} + +void BitsOfBinary::setMaximumAge(qint64 age) +{ + d_func()->maximumAge = age; +} + +QString BitsOfBinary::type() const +{ + return d_func()->type; +} + +void BitsOfBinary::setType(const QString &type) +{ + d_func()->type = type; +} + +QByteArray BitsOfBinary::data() const +{ + return d_func()->data; +} + +void BitsOfBinary::setData(const QByteArray &data) +{ + d_func()->data = data; +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/bitsofbinary.h
Added
@@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_BITSOFBINARY_H +#define JREEN_BITSOFBINARY_H + +#include "stanzaextension.h" + +namespace Jreen +{ + +class BitsOfBinaryPrivate; + +class JREEN_EXPORT BitsOfBinary : public Jreen::Payload +{ + J_PAYLOAD(Jreen::BitsOfBinary) + Q_DECLARE_PRIVATE(BitsOfBinary) +public: + BitsOfBinary(const QByteArray &data = QByteArray(), qint64 age = -1); + BitsOfBinary(const QUrl &cid); + ~BitsOfBinary(); + + QUrl cid() const; + void setCid(const QUrl &cid); + qint64 maximumAge() const; + void setMaximumAge(qint64 age); + QString type() const; + void setType(const QString &type); + QByteArray data() const; + void setData(const QByteArray &data); + +private: + QScopedPointer<BitsOfBinaryPrivate> d_ptr; +}; + +} // namespace Jreen + +#endif // JREEN_BITSOFBINARY_H
View file
libjreen-1.1.0.tar.bz2/src/bitsofbinaryfactory.cpp
Added
@@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "bitsofbinaryfactory_p.h" +#include <QUrl> +#include <QStringList> + +namespace Jreen +{ + +#define NS_BOB QLatin1String("urn:xmpp:bob") + +BitsOfBinaryFactory::BitsOfBinaryFactory() : m_depth(0) +{ +} + +QStringList BitsOfBinaryFactory::features() const +{ + return QStringList(); +} + +bool BitsOfBinaryFactory::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(attributes); + m_depth = 0; + return name == QLatin1String("data") && uri == NS_BOB; +} + +void BitsOfBinaryFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(name); + Q_UNUSED(uri); + ++m_depth; + + if (m_depth == 1) { + m_query.reset(new BitsOfBinary); + m_query->setCid(QUrl(attributes.value(QLatin1String("cid")).toString())); + QStringRef maxAgeString = attributes.value(QLatin1String("max-age")); + bool ok = true; + qint64 maxAge = maxAgeString.toString().toInt(&ok); + m_query->setMaximumAge(ok ? maxAge : -1); + m_query->setType(attributes.value(QLatin1String("type")).toString()); + } +} + +void BitsOfBinaryFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + Q_UNUSED(name); + Q_UNUSED(uri); + --m_depth; +} + +void BitsOfBinaryFactory::handleCharacterData(const QStringRef &text) +{ + if (m_depth == 1) + m_query->setData(QByteArray::fromBase64(text.toString().toLatin1())); +} + +void BitsOfBinaryFactory::serialize(Payload *extension, QXmlStreamWriter *writer) +{ + BitsOfBinary *query = payload_cast<BitsOfBinary*>(extension); + writer->writeStartElement(QLatin1String("data")); + writer->writeAttribute(QLatin1String("cid"), query->cid().toString()); + if (!query->type().isEmpty()) + writer->writeAttribute(QLatin1String("type"), query->type()); + if (query->maximumAge() >= 0) + writer->writeAttribute(QLatin1String("max-age"), QString::number(query->maximumAge())); + writer->writeDefaultNamespace(NS_BOB); + writer->writeCharacters(QLatin1String(query->data().toBase64())); + writer->writeEndElement(); +} + +Payload::Ptr BitsOfBinaryFactory::createPayload() +{ + return Payload::Ptr(m_query.take()); +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/bitsofbinaryfactory_p.h
Added
@@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_BITSOFBINARYFACTORY_P_H +#define JREEN_BITSOFBINARYFACTORY_P_H + +#include "bitsofbinary.h" + +namespace Jreen +{ + +class JREEN_AUTOTEST_EXPORT BitsOfBinaryFactory : public Jreen::PayloadFactory<BitsOfBinary> +{ +public: + BitsOfBinaryFactory(); + + QStringList features() const; + bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleEndElement(const QStringRef &name, const QStringRef &uri); + void handleCharacterData(const QStringRef &text); + void serialize(Payload *extension, QXmlStreamWriter *writer); + Payload::Ptr createPayload(); + +private: + int m_depth; + QScopedPointer<BitsOfBinary> m_query; +}; + +} // namespace Jreen + +#endif // JREEN_BITSOFBINARYFACTORY_P_H
View file
libjreen-1.0.3.tar.bz2/src/bookmarkfactory_p.h -> libjreen-1.1.0.tar.bz2/src/bookmarkfactory_p.h
Changed
@@ -29,7 +29,7 @@ namespace Jreen { -class BookmarkFactory : public PayloadFactory<Bookmark> +class JREEN_AUTOTEST_EXPORT BookmarkFactory : public PayloadFactory<Bookmark> { public: BookmarkFactory();
View file
libjreen-1.0.3.tar.bz2/src/capabilitiesfactory.cpp -> libjreen-1.1.0.tar.bz2/src/capabilitiesfactory.cpp
Changed
@@ -33,8 +33,7 @@ namespace Jreen { - -QString CapabilitesFactory::hashValue(Disco *disco) +QString CapabilitesFactory::verificationValue(Jreen::Disco *disco) { QString s; QStringList sl; @@ -72,6 +71,12 @@ s.append(value).append(QLatin1Char('<')); } } + return s; +} + +QString CapabilitesFactory::hashValue(Disco *disco) +{ + const QString s = verificationValue(disco); return QString::fromLatin1(QCryptographicHash::hash(s.toUtf8(), QCryptographicHash::Sha1).toBase64()); } @@ -122,9 +127,9 @@ QString ver = caps->ver().isEmpty() ? hashValue(m_disco) : caps->ver(); writer->writeStartElement(QLatin1String("c")); writer->writeDefaultNamespace(NS_CAPS); - writer->writeAttribute(QLatin1String("hash"),QLatin1String("sha-1")); - writer->writeAttribute(QLatin1String("ver"),ver); - writer->writeAttribute(QLatin1String("node"),caps->node()); + writer->writeAttribute(QLatin1String("hash"), QLatin1String("sha-1")); + writer->writeAttribute(QLatin1String("ver"), ver); + writer->writeAttribute(QLatin1String("node"), caps->node()); writer->writeEndElement(); }
View file
libjreen-1.0.3.tar.bz2/src/capabilitiesfactory_p.h -> libjreen-1.1.0.tar.bz2/src/capabilitiesfactory_p.h
Changed
@@ -32,7 +32,7 @@ namespace Jreen { class Disco; -class CapabilitesFactory : public PayloadFactory<Capabilities> +class JREEN_AUTOTEST_EXPORT CapabilitesFactory : public PayloadFactory<Capabilities> { public: CapabilitesFactory(Disco *disco); @@ -44,6 +44,7 @@ void handleCharacterData(const QStringRef &text); void serialize(Payload *extension, QXmlStreamWriter *writer); Payload::Ptr createPayload(); + static QString verificationValue(Disco *disco); static QString hashValue(Disco *disco); private: Disco *m_disco;
View file
libjreen-1.1.0.tar.bz2/src/captcha.cpp
Added
@@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "captcha.h" + +namespace Jreen { + +class CaptchaPrivate +{ +public: + DataForm::Ptr form; +}; + +Captcha::Captcha(DataForm::Ptr form) : d_ptr(new CaptchaPrivate) +{ + d_func()->form = form; +} + +Captcha::~Captcha() +{ +} + +DataForm::Ptr Captcha::form() const +{ + return d_func()->form; +} + +void Captcha::setForm(const DataForm::Ptr &form) +{ + d_func()->form = form; +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/captcha.h
Added
@@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_CAPTCHA_H +#define JREEN_CAPTCHA_H + +#include "dataform.h" + +namespace Jreen { + +class CaptchaPrivate; + +class JREEN_EXPORT Captcha : public Payload +{ + J_PAYLOAD(Jreen::Captcha) + Q_DECLARE_PRIVATE(Captcha) +public: + Captcha(DataForm::Ptr form = DataForm::Ptr()); + ~Captcha(); + + DataForm::Ptr form() const; + void setForm(const DataForm::Ptr &form); + +private: + QScopedPointer<CaptchaPrivate> d_ptr; +}; + +} // namespace Jreen + +#endif // JREEN_CAPTCHA_H
View file
libjreen-1.1.0.tar.bz2/src/captchafactory.cpp
Added
@@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "captchafactory_p.h" + +#define NS_CAPTCHA QLatin1String("urn:xmpp:captcha") + +namespace Jreen { + +CaptchaFactory::CaptchaFactory() : m_depth(0), m_atFactory(0) +{ +} + +QStringList CaptchaFactory::features() const +{ + return QStringList(); +} + +bool CaptchaFactory::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(attributes); + return name == QLatin1String("captcha") && uri == NS_CAPTCHA; +} + +void CaptchaFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + ++m_depth; + + if (m_depth == 1) + m_captcha.reset(new Captcha); + else if (m_depth == 2 && m_factory.canParse(name, uri, attributes)) + m_atFactory = true; + + if (m_atFactory) + m_factory.handleStartElement(name, uri, attributes); +} + +void CaptchaFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + if (m_atFactory) { + m_factory.handleEndElement(name, uri); + if (m_depth == 2) { + DataForm::Ptr form = m_factory.createPayload().staticCast<DataForm>(); + if (form->typeName() == NS_CAPTCHA) + m_captcha->setForm(form); + m_atFactory = false; + } + } + + --m_depth; +} + +void CaptchaFactory::handleCharacterData(const QStringRef &text) +{ + if (m_atFactory) + m_factory.handleCharacterData(text); +} + +void CaptchaFactory::serialize(Payload *extension, QXmlStreamWriter *writer) +{ + Captcha *captcha = payload_cast<Captcha*>(extension); + writer->writeStartElement(QLatin1String("captcha")); + writer->writeDefaultNamespace(NS_CAPTCHA); + if (captcha->form()) + m_factory.serialize(captcha->form().data(), writer); + writer->writeEndElement(); +} + +Payload::Ptr CaptchaFactory::createPayload() +{ + return Payload::Ptr(m_captcha.take()); +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/captchafactory_p.h
Added
@@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_CAPTCHAFACTORY_P_H +#define JREEN_CAPTCHAFACTORY_P_H + +#include "captcha.h" +#include "dataformfactory_p.h" + +namespace Jreen { + +class JREEN_AUTOTEST_EXPORT CaptchaFactory : public PayloadFactory<Captcha> +{ +public: + CaptchaFactory(); + + QStringList features() const; + bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleEndElement(const QStringRef &name, const QStringRef &uri); + void handleCharacterData(const QStringRef &text); + void serialize(Payload *extension, QXmlStreamWriter *writer); + Payload::Ptr createPayload(); + +private: + int m_depth : 31; + int m_atFactory : 1; + DataFormFactory m_factory; + QScopedPointer<Captcha> m_captcha; +}; + +} // namespace Jreen + +#endif // JREEN_CAPTCHAFACTORY_P_H
View file
libjreen-1.0.3.tar.bz2/src/chatstatefactory_p.h -> libjreen-1.1.0.tar.bz2/src/chatstatefactory_p.h
Changed
@@ -30,7 +30,7 @@ namespace Jreen { -class ChatStateFactory : public PayloadFactory<ChatState> +class JREEN_AUTOTEST_EXPORT ChatStateFactory : public PayloadFactory<ChatState> { public: ChatStateFactory();
View file
libjreen-1.0.3.tar.bz2/src/client.cpp -> libjreen-1.1.0.tar.bz2/src/client.cpp
Changed
@@ -43,6 +43,7 @@ #include "pubsubmanager_p.h" #include "tunefactory_p.h" #include "bookmarkfactory_p.h" +#include "metacontactsfactory_p.h" #include "privacyqueryfactory_p.h" #include "delayeddeliveryfactory_p.h" #include "receiptfactory_p.h" @@ -58,6 +59,11 @@ #include "chatstatefactory_p.h" #include "capabilitiesfactory_p.h" #include "errorfactory_p.h" +#include "registrationqueryfactory_p.h" +#include "bitsofbinaryfactory_p.h" +#include "captchafactory_p.h" +#include "pgpfactory_p.h" +#include "forwardedfactory_p.h" // Features #include "nonsaslauth_p.h" @@ -84,11 +90,12 @@ int type = StanzaPrivate::get(*stanza)->type; if (type == StanzaPrivate::StanzaIq) { QSharedPointer<IQ> iq = stanza.staticCast<IQ>(); - IQReply *reply = iqTracks.take(stanza->id()); - if (reply) { - emit reply->received(*iq); - reply->deleteLater(); - } else { + if (iq->subtype() == IQ::Result || iq->subtype() == IQ::Error) { + if (IQReply *reply = iqTracks.take(stanza->id())) { + emit reply->received(*iq); + reply->deleteLater(); + } + } else if (iq->subtype() == IQ::Get || iq->subtype() == IQ::Set) { bool ok = iq->from().isDomain() || !roster || rooms.contains(iq->from().bare()) @@ -108,7 +115,7 @@ return; } q_ptr->handleIQ(*iq); - if (!iq->accepted() && (iq->subtype() == IQ::Set || iq->subtype() == IQ::Get)) { + if (!iq->accepted()) { IQ error(IQ::Error, iq->from(), iq->id()); error.addExtension(new Error(Error::Cancel, Error::ServiceUnavailable)); send(error); @@ -163,11 +170,15 @@ q_ptr->registerPayload(new MUCRoomOwnerQueryFactory); q_ptr->registerPayload(new EntityTimeFactory); q_ptr->registerPayload(new BookmarkFactory); + q_ptr->registerPayload(new MetaContactsFactory); q_ptr->registerPayload(new PrivateXmlQueryFactory(q_ptr)); q_ptr->registerPayload(new PrivacyQueryFactory); -// client->registerPayload(new PubSub::EventFactory); -// client->registerPayload(new PubSub::PublishFacatory); - //client->registerPayload(new PrivateXml::QueryFactory); + q_ptr->registerPayload(new RegistrationQueryFactory); + q_ptr->registerPayload(new BitsOfBinaryFactory); + q_ptr->registerPayload(new CaptchaFactory); + q_ptr->registerPayload(new PGPSignedFactory); + q_ptr->registerPayload(new PGPEncryptedFactory); + q_ptr->registerPayload(new ForwardedFactory(q_ptr)); q_ptr->registerStreamFeature(new NonSaslAuth); q_ptr->registerStreamFeature(new SASLFeature); @@ -175,7 +186,7 @@ q_ptr->registerStreamFeature(new BindFeature); q_ptr->registerStreamFeature(new SessionFeature); q_ptr->registerStreamFeature(new ZLibCompressionFeature); - presence.addExtension(new Capabilities(QString(), QLatin1String("http://qutim.org/jreen/"))); + presence.addExtension(new Capabilities(QString(), QLatin1String("http://qutim.org/jreen"))); } Client::Client(const JID &jid, const QString &password, int port) @@ -236,6 +247,26 @@ d->proxy = proxy; } +void Client::setFeatureConfig(Client::Feature feature, Client::FeatureConfig config) +{ + Q_D(Client); + if (feature < 0 || feature >= d->configs.size()) + return; + d->configsfeature = config; +} + +Client::FeatureConfig Client::featureConfig(Client::Feature feature) const +{ + Q_D(const Client); + return d->configs.value(feature, Auto); +} + +bool Client::isFeatureActivated(Client::Feature feature) const +{ + Q_D(const Client); + return (d->usedFeatures & (1 << feature)); +} + QNetworkProxy Client::proxy() const { return d_func()->proxy; @@ -243,7 +274,6 @@ void Client::setProxyFactory(QNetworkProxyFactory *factory) { - Q_D(Client); d_func()->proxyFactory.reset(factory); } @@ -310,6 +340,14 @@ return d_func()->roster; } +JingleManager *Client::jingleManager() +{ + Q_D(Client); + if (!d->jingleManager) + d->jingleManager.reset(new JingleManager(this)); + return d->jingleManager.data(); +} + void Client::send(const Stanza &stanza) { Q_D(Client); @@ -383,10 +421,11 @@ delete d->conn; d->conn = conn; d->streamProcessor = qobject_cast<StreamProcessor*>(conn); - d->device->setDevice(conn); + d->bufferedDevice->setDevice(conn); // connect(conn, SIGNAL(readyRead()), impl, SLOT(newData())); connect(conn, SIGNAL(connected()), this, SLOT(_q_connected())); - connect(conn, SIGNAL(disconnected()), this, SLOT(_q_disconnected())); + connect(conn, SIGNAL(stateChanged(Jreen::Connection::SocketState)), + this, SLOT(_q_stateChanged(Jreen::Connection::SocketState))); } Connection *Client::connection() const @@ -410,14 +449,21 @@ return a->type() == b->type() ? a->priority() > b->priority() : a->type() < b->type(); } -void Client::registerStreamFeature(StreamFeature *stream_feature) +void Client::registerStreamFeature(StreamFeature *streamFeature) { Q_D(Client); - if(!stream_feature) + if(!streamFeature) return; d->features.insert(qLowerBound(d->features.begin(), d->features.end(), - stream_feature, featureLessThan), stream_feature); - stream_feature->setStreamInfo(d->stream_info); + streamFeature, featureLessThan), streamFeature); + streamFeature->setStreamInfo(d->stream_info); +} + +void Client::removeStreamFeature(StreamFeature *streamFeature) +{ + Q_D(Client); + d->features.removeAll(streamFeature); + streamFeature->setStreamInfo(0); } void Client::setPingInterval(int interval)
View file
libjreen-1.0.3.tar.bz2/src/client.h -> libjreen-1.1.0.tar.bz2/src/client.h
Changed
@@ -33,7 +33,7 @@ #include "presence.h" #include "disco.h" -class QNetworkProxyFactory; +class JREEN_AUTOTEST_EXPORT QNetworkProxyFactory; class QNetworkProxy; namespace Jreen @@ -49,6 +49,7 @@ class Disco; class MessageSessionManager; class AbstractRoster; +class JingleManager; class XmlStreamHandler { @@ -80,8 +81,26 @@ InternalServerError, SystemShutdown, Conflict, - Unknown + Unknown, + NoCompressionSupport, + NoEncryptionSupport, + NoAuthorizationSupport, + NoSupportedFeature }; + + enum Feature { + InvalidFeature = -1, + Compression = 0, + Encryption, + Authorization + }; + + enum FeatureConfig { + Force, + Disable, + Auto + }; + Client(const JID &jid, const QString &password = QString(), int port = -1); Client(); virtual ~Client(); @@ -93,6 +112,9 @@ void setResource(const QString &resource); void setPort(int port); void setProxy(const QNetworkProxy &proxy); + void setFeatureConfig(Feature feature, FeatureConfig config); + FeatureConfig featureConfig(Feature feature) const; + bool isFeatureActivated(Feature feature) const; QNetworkProxy proxy() const; void setProxyFactory(QNetworkProxyFactory *factory); QNetworkProxyFactory *proxyFactory() const; @@ -107,6 +129,7 @@ Disco *disco(); MessageSessionManager *messageSessionManager(); AbstractRoster *roster(); + JingleManager *jingleManager(); bool isConnected() const; void send(const Stanza &stanza); void send(const Presence &pres); @@ -115,7 +138,8 @@ void setConnection(Connection *conn); Connection *connection() const; void registerPayload(AbstractPayloadFactory *factory); - void registerStreamFeature(StreamFeature *stream_feature); + void registerStreamFeature(StreamFeature *streamFeature); + void removeStreamFeature(StreamFeature *streamFeature); public slots: void setPresence(); void setPresence(Jreen::Presence::Type type, const QString &text = QString(), int priority = -129); @@ -146,7 +170,7 @@ Q_PRIVATE_SLOT(d_func(), void _q_read_more()) Q_PRIVATE_SLOT(d_func(), void _q_send_header()) Q_PRIVATE_SLOT(d_func(), void _q_connected()) - Q_PRIVATE_SLOT(d_func(), void _q_disconnected()) + Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(Jreen::Connection::SocketState)) }; }
View file
libjreen-1.0.3.tar.bz2/src/client_p.h -> libjreen-1.1.0.tar.bz2/src/client_p.h
Changed
@@ -51,6 +51,7 @@ #include <QNetworkProxyFactory> #include "stanza_p.h" #include "streamprocessor.h" +#include "experimental/jinglemanager.h" namespace Jreen { @@ -131,28 +132,32 @@ roster = 0; authorized = false; isConnected = false; - device = new BufferedDataStream(&streamHandlers); - device->open(QIODevice::ReadWrite); - q->connect(device, SIGNAL(readyRead()), q, SLOT(_q_new_data())); + bufferedDevice.reset(new BufferedDataStream(&streamHandlers)); + bufferedDevice->open(QIODevice::ReadWrite); + q->connect(bufferedDevice.data(), SIGNAL(readyRead()), q, SLOT(_q_new_data())); + configs.append(Client::Auto); + configs.append(Client::Auto); + configs.append(Client::Force); + usedFeatures = 0; } void init(); void send(const Stanza &stanza) { - if(stanza.from().full().isEmpty()) { + if(isConnected && stanza.from().full().isEmpty()) { const StanzaPrivate *p = StanzaPrivate::get(stanza); const_cast<StanzaPrivate*>(p)->from = jid; } foreach (StanzaFactory *factory, stanzas) { if (factory->stanzaType() == StanzaPrivate::get(stanza)->type) { - factory->serialize(const_cast<Stanza*>(&stanza), writer); + factory->serialize(const_cast<Stanza*>(&stanza), writer.data()); break; } } } void send(const QString &data) { - if(conn && device->isOpen()) - device->write(data.toUtf8()); + if(conn && bufferedDevice->isOpen()) + bufferedDevice->write(data.toUtf8()); } void processStreamFeature(StreamFeature *stream_feature) { @@ -183,7 +188,7 @@ int current_id; Parser *parser; Connection *conn; - DataStream *device; + QScopedPointer<BufferedDataStream> bufferedDevice; StreamProcessor *streamProcessor; QList<DataStream*> devices; bool authorized; @@ -192,22 +197,25 @@ Disco *disco; StreamFeature *current_stream_feature; QHash<QString, IQReply*> iqTracks; - QXmlStreamWriter *writer; + QScopedPointer<QXmlStreamWriter> writer; + QVector<Client::FeatureConfig> configs; + int usedFeatures; QList<StanzaFactory*> stanzas; QList<StreamFeature*> features; QSet<QString> serverFeatures; Jreen::Disco::IdentityList serverIdentities; - QMap<QString, MUCRoomPrivate*> rooms; + QHash<QString, MUCRoomPrivate*> rooms; PayloadFactoryMap factories; - QMultiMap<QString, AbstractPayloadFactory*> factoriesByUri; + QMultiHash<QString, AbstractPayloadFactory*> factoriesByUri; MessageSessionManager *messageSessionManager; AbstractRoster *roster; + QScopedPointer<JingleManager> jingleManager; int depth; IQReply *createIQReply() { return new IQReply(q_func()); } void _q_iq_received(const Jreen::IQ &iq, int context); void _q_new_data() { - QByteArray data = device->read(qMax(Q_INT64_C(0xffff), device->bytesAvailable())); // device->readAll(); + QByteArray data = bufferedDevice->read(qMax(Q_INT64_C(0xffff), bufferedDevice->bytesAvailable())); // device->readAll(); // Logger::debug() << "-" << data.size() << data; parser->appendData(data); // parser->appendData(data); @@ -216,24 +224,13 @@ void _q_read_more(); void _q_send_header() { - delete writer; foreach (XmlStreamHandler *handler, streamHandlers) handler->handleStreamBegin(); if (streamProcessor) { - writer = new QXmlStreamWriter(device); -// QByteArray data; -// QBuffer buffer(&data); -// buffer.open(QIODevice::WriteOnly); -// streamProcessor->restartStream(); -// writer = new QXmlStreamWriter(&buffer); -// writer->writeStartDocument(QLatin1String("1.0")); -// writer->writeStartElement(QLatin1String("stream:stream")); -// writer->writeDefaultNamespace(QLatin1String("jabber:client")); -// writer->writeCharacters(QString()); -// writer->setDevice(device); + writer.reset(new QXmlStreamWriter(bufferedDevice.data())); return; } - writer = new QXmlStreamWriter(device); + writer.reset(new QXmlStreamWriter(bufferedDevice.data())); writer->writeStartDocument(QLatin1String("1.0")); writer->writeStartElement(QLatin1String("stream:stream")); writer->writeAttribute(QLatin1String("to"), jid.domain()); @@ -254,16 +251,16 @@ void _q_connected() { - writer = 0; + writer.reset(); depth = 0; parser->reset(); _q_send_header(); - isConnected = true; } void _q_disconnected() { pingTimer.stop(); isConnected = false; + usedFeatures = 0; foreach (XmlStreamHandler *handler, streamHandlers) handler->handleStreamEnd(); authorized = false; @@ -273,17 +270,29 @@ foreach (DataStream *dataStream, devices) dataStream->deleteLater(); devices.clear(); - device->setDevice(conn); + bufferedDevice->setDevice(conn); QHash<QString, IQReply*>::iterator it = iqTracks.begin(); for (; it != iqTracks.end(); ++it) it.value()->deleteLater(); iqTracks.clear(); } - inline void emitAuthorized() { q_ptr->handleAuthorized(); } + void _q_stateChanged(Connection::SocketState state) + { + if (state == Connection::UnconnectedState) + _q_disconnected(); + } + + inline void emitAuthorized() { authorized = true; q_ptr->handleAuthorized(); } inline void emitConnected() { isConnected = true; q_ptr->handleConnect(); } inline void emitDisconnected(Client::DisconnectReason reason) { - emit q_func()->disconnected(reason); + Q_Q(Client); + writer->writeEndElement(); + q->blockSignals(true); + conn->close(); + _q_disconnected(); + q->blockSignals(false); + emit q->disconnected(reason); } }; @@ -328,7 +337,7 @@ } QXmlStreamWriter *writer() { - return d->writer; + return d->writer.data(); } void completed(const CompletedFlags &flags) { @@ -339,7 +348,7 @@ if(flags & Authorized) d->emitAuthorized(); if (flags & ResendHeader) { - d->device->readAll(); + d->bufferedDevice->readAll(); d->_q_send_header(); if (d->streamProcessor) d->streamProcessor->restartStream(); @@ -363,8 +372,8 @@ void addDataStream(DataStream *dataStream) { d->devices.append(dataStream); - dataStream->setDevice(d->device->device()); - d->device->setDevice(dataStream); + dataStream->setDevice(d->bufferedDevice->device()); + d->bufferedDevice->setDevice(dataStream); // QObject::disconnect(m_client_private->device, 0, m_client_private, 0); // m_client_private->device = dataStream; dataStream->open(QIODevice::ReadWrite);
View file
libjreen-1.0.3.tar.bz2/src/dataform.cpp -> libjreen-1.1.0.tar.bz2/src/dataform.cpp
Changed
@@ -26,11 +26,139 @@ #include "dataform_p.h" #include "jstrings.h" +#include "stanza.h" +#include "bitsofbinary.h" #include <QStringList> +#include <QSize> +#include <QUrl> namespace Jreen { +class DataFormMedia::UriPrivate : public QSharedData +{ +public: + UriPrivate() {} + UriPrivate(const UriPrivate &o) : QSharedData(o), url(o.url), type(o.type) {} + + QUrl url; + QString type; +}; + +DataFormMedia::Uri::Uri() : d(new UriPrivate) +{ +} + +DataFormMedia::Uri::Uri(const QUrl &url, const QString &type) : d(new UriPrivate) +{ + d->url = url; + d->type = type; +} + +DataFormMedia::Uri::Uri(const DataFormMedia::Uri &o) : d(o.d) +{ +} + +DataFormMedia::Uri &DataFormMedia::Uri::operator =(const DataFormMedia::Uri &o) +{ + d = o.d; + return *this; +} + +DataFormMedia::Uri::~Uri() +{ +} + +bool DataFormMedia::Uri::operator ==(const DataFormMedia::Uri &o) const +{ + return d->type == o.d->type && d->url == o.d->url; +} + +QUrl DataFormMedia::Uri::url() const +{ + return d->url; +} + +void DataFormMedia::Uri::setUrl(const QUrl &url) +{ + d->url = url; +} + +QString DataFormMedia::Uri::type() const +{ + return d->type; +} + +void DataFormMedia::Uri::setType(const QString &type) +{ + d->type = type; +} + +class DataFormMediaPrivate +{ +public: + QSize size; + QList<DataFormMedia::Uri> uries; +}; + +DataFormMedia::DataFormMedia() : d_ptr(new DataFormMediaPrivate) +{ +} + +DataFormMedia::~DataFormMedia() +{ +} + +void DataFormMedia::appendUri(const DataFormMedia::Uri &uri) +{ + d_func()->uries.append(uri); +} + +void DataFormMedia::appendUri(const QUrl &url, const QString &type) +{ + d_func()->uries.append(Uri(url, type)); +} + +void DataFormMedia::setUries(const QList<DataFormMedia::Uri> &uries) +{ + d_func()->uries = uries; +} + +QList<DataFormMedia::Uri> DataFormMedia::uries() const +{ + return d_func()->uries; +} + +QSize DataFormMedia::size() const +{ + return d_func()->size; +} + +void DataFormMedia::setSize(const QSize &size) +{ + d_func()->size = size; +} + +int DataFormMedia::width() const +{ + return d_func()->size.width(); +} + +void DataFormMedia::setWidth(int width) +{ + d_func()->size.setWidth(width); +} + +int DataFormMedia::height() const +{ + return d_func()->size.height(); +} + +void DataFormMedia::setHeight(int height) +{ + d_func()->size.setHeight(height); +} + DataFormField::DataFormField(Type type, const QString &var, const QString &label) : d_ptr(new DataFormFieldPrivate) { d_ptr->type = type; @@ -97,6 +225,16 @@ d_ptr->desc = desc; } +DataFormMedia::Ptr DataFormField::media() const +{ + return d_ptr->media; +} + +void DataFormField::setMedia(const DataFormMedia::Ptr &media) +{ + d_ptr->media = media; +} + void DataFormField::setValues(const QStringList &values) { d_ptr->values = values; @@ -466,6 +604,14 @@ d->title = title; } +DataForm::DataForm(DataForm::Type type, const QString &title, const QString &instructions) : DataFormFieldContainer(*new DataFormPrivate) +{ + Q_D(DataForm); + d->type = type; + d->title = title; + d->instructions = instructions; +} + DataForm::~DataForm() { } @@ -502,6 +648,11 @@ return d_func()->title; } +QString DataForm::instructions() const +{ + return d_func()->instructions; +} + QList<DataFormItem::Ptr> DataForm::items() const { return d_func()->items;
View file
libjreen-1.0.3.tar.bz2/src/dataform.h -> libjreen-1.1.0.tar.bz2/src/dataform.h
Changed
@@ -40,11 +40,61 @@ // http://xmpp.org/extensions/xep-0004.html class DataFormFieldPrivate; +class DataFormMediaPrivate; +class Stanza; + +class JREEN_EXPORT DataFormMedia +{ + Q_DECLARE_PRIVATE(DataFormMedia) +public: + typedef QSharedPointer<DataFormMedia> Ptr; + + class UriPrivate; + class JREEN_EXPORT Uri + { + public: + Uri(); + Uri(const QUrl &url, const QString &type); + Uri(const Uri &o); + Uri &operator =(const Uri &o); + ~Uri(); + + bool operator==(const Uri &o) const; + + QUrl url() const; + void setUrl(const QUrl &url); + QString type() const; + void setType(const QString &type); + private: + QSharedDataPointer<UriPrivate> d; + }; + + DataFormMedia(); + ~DataFormMedia(); + + void appendUri(const Uri &uri); + void appendUri(const QUrl &url, const QString &type); + void setUries(const QList<Uri> &uries); + QList<Uri> uries() const; + + QSize size() const; + void setSize(const QSize &size); + int width() const; + void setWidth(int width); + int height() const; + void setHeight(int height); + +private: + Q_DISABLE_COPY(DataFormMedia) + QScopedPointer<DataFormMediaPrivate> d_ptr; +}; + class JREEN_EXPORT DataFormField { public: enum Type { + Invalid = -1, Boolean, /**< The field enables an entity to gather or provide an either-or * choice between two options. The default value is "false". */ Fixed, /**< The field is intended for data description (e.g., human-readable @@ -82,8 +132,7 @@ * line or word of text, which may be shown in an interface. * This field type is the default and MUST be assumed if a form-submitting * entity receives a field type it does not understand. */ - None, - Invalid + None }; DataFormField(Type type = Invalid, const QString &var = QString(), const QString &label = QString()); @@ -101,6 +150,9 @@ QString description() const; void setDescription(const QString &desc); + DataFormMedia::Ptr media() const; + void setMedia(const DataFormMedia::Ptr &media); + void setValues(const QStringList &values); QStringList values() const; void setValue(const QString &value); @@ -329,6 +381,7 @@ Invalid }; DataForm(Type type = Submit, const QString &title = QString()); + DataForm(Type type, const QString &title, const QString &instructions); virtual ~DataForm(); Type type() const; @@ -336,6 +389,7 @@ QString typeName() const; void setTypeName(const QString &type); QString title() const; + QString instructions() const; QList<DataFormItem::Ptr> items() const; DataFormReported::Ptr reported() const; };
View file
libjreen-1.0.3.tar.bz2/src/dataform_p.h -> libjreen-1.1.0.tar.bz2/src/dataform_p.h
Changed
@@ -45,6 +45,7 @@ QStringList values; bool required; QList<QPair<QString,QString> > options; + DataFormMedia::Ptr media; static DataFormFieldPrivate *get(DataFormField *field) { return field->d_ptr.data(); } private: @@ -71,6 +72,7 @@ { public: QString title; + QString instructions; DataFormReported::Ptr reported; QList<DataFormItem::Ptr> items; DataForm::Type type;
View file
libjreen-1.0.3.tar.bz2/src/dataformfactory.cpp -> libjreen-1.1.0.tar.bz2/src/dataformfactory.cpp
Changed
@@ -26,10 +26,12 @@ #include "dataformfactory_p.h" #include "jstrings.h" #include <QXmlStreamWriter> +#include <QSize> +#include <QUrl> #include "util.h" -#include "multimediadatafactory_p.h" #include "logger.h" #define NS_DATAFORM QLatin1String("jabber:x:data") +#define NS_MEDIA QLatin1String("urn:xmpp:media-element") namespace Jreen { @@ -110,6 +112,86 @@ QString m_value; }; +class DataFormMediaParser : public XmlStreamFactory<DataFormMedia> +{ +public: + DataFormMediaParser() : m_depth(0), m_state(AtNowhere) + { + } + + virtual ~DataFormMediaParser() + { + } + + virtual bool canParse(const QStringRef &name, const QStringRef &uri, + const QXmlStreamAttributes &attributes) + { + Q_UNUSED(attributes); + return name == QLatin1String("media") && uri == NS_MEDIA; + } + virtual void handleStartElement(const QStringRef &name, const QStringRef &uri, + const QXmlStreamAttributes &attributes) + { + Q_UNUSED(name); + Q_UNUSED(uri); + m_depth++; + + if(m_depth == 1) { + m_state = AtNowhere; + m_media = DataFormMedia::Ptr::create(); + } else if (m_depth == 2 && name == QLatin1String("uri")) { + m_state = AtUri; + m_uriType = attributes.value(QLatin1String("type")).toString(); + } + } + virtual void handleEndElement(const QStringRef &name, const QStringRef &uri) + { + Q_UNUSED(name); + Q_UNUSED(uri); + if (m_depth == 2) + m_state = AtNowhere; + m_depth--; + } + virtual void handleCharacterData(const QStringRef &text) + { + if(m_depth == 2 && m_state == AtUri) { + m_media->appendUri(text.toString(), m_uriType); + } + } + virtual void serialize(DataFormMedia *media, QXmlStreamWriter *writer) + { + writer->writeStartElement(QLatin1String("media")); + const QSize size = media->size(); + if (size.width() >= 0) + writer->writeAttribute(QLatin1String("width"), QString::number(size.width())); + if (size.height() >= 0) + writer->writeAttribute(QLatin1String("height"), QString::number(size.height())); + writer->writeDefaultNamespace(NS_MEDIA); + foreach (const DataFormMedia::Uri &uri, media->uries()) { + writer->writeStartElement(QLatin1String("uri")); + writer->writeAttribute(QLatin1String("type"), uri.type()); + writer->writeCharacters(uri.url().toString()); + writer->writeEndElement(); + } + writer->writeEndElement(); + } + DataFormMedia::Ptr create() + { + DataFormMedia::Ptr result; + qSwap(result, m_media); + return result; + } + +private: + int m_depth; + enum State { + AtNowhere, + AtUri + } m_state; + QString m_uriType; + DataFormMedia::Ptr m_media; +}; + static const char* datafield_types = { "boolean", "fixed", @@ -120,7 +202,8 @@ "list-single", "text-multi", "text-private", - "text-single" + "text-single", + "" }; class DataFormFieldParser : XmlStreamFactory<DataFormField> @@ -155,6 +238,8 @@ m_state = AtValue; } else if(m_optionParser.canParse(name,uri,attributes)) { m_state = AtOption; + } else if (m_mediaParser.canParse(name, uri, attributes)) { + m_state = AtMedia; } else if(name == QLatin1String("required")) { m_state = AtRequied; m_required = true; @@ -164,6 +249,8 @@ } if(m_state == AtOption) m_optionParser.handleStartElement(name,uri,attributes); + else if(m_state == AtMedia) + m_mediaParser.handleStartElement(name, uri, attributes); } virtual void handleEndElement(const QStringRef &name, const QStringRef &uri) { @@ -173,6 +260,10 @@ Logger::debug() << m_optionParser.create(); m_options.append(m_optionParser.create()); } + } else if(m_state == AtMedia) { + m_mediaParser.handleEndElement(name, uri); + if(m_depth == 2) + m_media = m_mediaParser.create(); } if (m_depth <= 2) m_state = AtNowhere; @@ -186,6 +277,10 @@ break; case AtOption: m_optionParser.handleCharacterData(text); + break; + case AtMedia: + m_mediaParser.handleCharacterData(text); + break; default: break; } @@ -219,8 +314,8 @@ d->label = m_label; d->type = m_type; d->options = m_options; -// Logger::debug() << m_label << m_var << field.var() << field.label() << d->var << d->label; d->required = m_required; + d->media = m_media; clear(); return field; } @@ -229,6 +324,7 @@ AtValue, AtOption, AtRequied, + AtMedia, AtNowhere }; void clear() { @@ -237,10 +333,12 @@ m_label.clear(); m_var.clear(); m_values.clear(); + m_media.clear(); m_required = false; m_state = AtNowhere; } State m_state; +// QScopedPointer<DataFormFieldPrivate> m_form; int m_depth; DataFormField::Type m_type; QString m_label; @@ -248,8 +346,9 @@ QStringList m_values; QList<QPair<QString, QString> > m_options; bool m_required; + DataFormMedia::Ptr m_media; DataFormOptionParser m_optionParser; - MultimediaDataFactory m_multimediaDataFactory; + DataFormMediaParser m_mediaParser; }; enum DataFormState { AtNowhere, AtTitle, AtInstruction, AtField }; @@ -267,7 +366,7 @@ "result" }; -class DataFormFactoryPrivate +class JREEN_AUTOTEST_EXPORT DataFormFactoryPrivate { public: void clear() @@ -320,7 +419,7 @@ d->state = AtField; else if(name == QLatin1String("title")) d->state = AtTitle; - else if(name == QLatin1String("instruction")) + else if(name == QLatin1String("instructions")) d->state = AtInstruction; else d->state = AtNowhere; @@ -350,10 +449,13 @@ switch(d->state) { case AtTitle: d->title = text.toString(); + break; case AtInstruction: d->instruction = text.toString(); + break; case AtField: d->fieldParser.handleCharacterData(text); + break; default: break; } @@ -376,7 +478,7 @@ Payload::Ptr DataFormFactory::createPayload() { Q_D(DataFormFactory); - DataForm *form = new DataForm(d->formType,d->title); + DataForm *form = new DataForm(d->formType, d->title, d->instruction); form->setFields(d->fields); d->clear(); return Payload::Ptr(form);
View file
libjreen-1.0.3.tar.bz2/src/dataformfactory_p.h -> libjreen-1.1.0.tar.bz2/src/dataformfactory_p.h
Changed
@@ -29,8 +29,8 @@ namespace Jreen { -class DataFormFactoryPrivate; -class DataFormFactory : public PayloadFactory<DataForm> +class JREEN_AUTOTEST_EXPORT DataFormFactoryPrivate; +class JREEN_AUTOTEST_EXPORT DataFormFactory : public PayloadFactory<DataForm> { Q_DECLARE_PRIVATE(DataFormFactory) public:
View file
libjreen-1.0.3.tar.bz2/src/delayeddeliveryfactory.cpp -> libjreen-1.1.0.tar.bz2/src/delayeddeliveryfactory.cpp
Changed
@@ -28,12 +28,12 @@ #include "util.h" -#define NS_DELAY "urn:xmpp:delay" -#define NS_DELAY_DEPRECATED "jabber:x:delay" +#define NS_DELAY QLatin1String("urn:xmpp:delay") +#define NS_DELAY_DEPRECATED QLatin1String("jabber:x:delay") namespace Jreen { -class DelayedDeliveryFactoryPrivate +class JREEN_AUTOTEST_EXPORT DelayedDeliveryFactoryPrivate { public: JID from; @@ -90,7 +90,8 @@ writer->writeStartElement(QLatin1String("delay")); writer->writeAttribute(QLatin1String("stamp"), Util::toStamp(delivery->dateTime())); writer->writeDefaultNamespace(NS_DELAY); - writer->writeAttribute(QLatin1String("from"), delivery->from()); + if (delivery->from().isValid()) + writer->writeAttribute(QLatin1String("from"), delivery->from()); writer->writeCharacters(delivery->reason()); writer->writeEndElement(); }
View file
libjreen-1.0.3.tar.bz2/src/delayeddeliveryfactory_p.h -> libjreen-1.1.0.tar.bz2/src/delayeddeliveryfactory_p.h
Changed
@@ -29,8 +29,8 @@ namespace Jreen { -class DelayedDeliveryFactoryPrivate; -class DelayedDeliveryFactory : public PayloadFactory<DelayedDelivery> +class JREEN_AUTOTEST_EXPORT DelayedDeliveryFactoryPrivate; +class JREEN_AUTOTEST_EXPORT DelayedDeliveryFactory : public PayloadFactory<DelayedDelivery> { Q_DECLARE_PRIVATE(DelayedDeliveryFactory) public:
View file
libjreen-1.0.3.tar.bz2/src/directconnection.cpp -> libjreen-1.1.0.tar.bz2/src/directconnection.cpp
Changed
@@ -29,9 +29,128 @@ #include <QSslConfiguration> #include <QSsl> +#ifdef Q_OS_LINUX +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <netinet/tcp.h> +#endif + namespace Jreen { +DirectConnectionPrivate::DirectConnectionPrivate(const QString &hn, int p, DirectConnection *par) + : host_name(hn), port(p), dns_lookup_id(-1), parent(par) +{ + do_lookup = p < 0 || !QUrl(host_name).isValid(); + socket_state = QAbstractSocket::UnconnectedState; + socket_error = QAbstractSocket::UnknownSocketError; +} + +void DirectConnectionPrivate::connectSocket() +{ + if (qobject_cast<QSslSocket*>(socket)) { + connect(socket, SIGNAL(encrypted()), parent, SIGNAL(connected())); + } else { + connect(socket, SIGNAL(connected()), parent, SIGNAL(connected())); + } + connect(socket, SIGNAL(disconnected()), parent, SIGNAL(disconnected())); + connect(socket, SIGNAL(readyRead()), parent, SIGNAL(readyRead())); + connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), + this, SLOT(stateChanged(QAbstractSocket::SocketState))); + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(error(QAbstractSocket::SocketError))); + connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + parent, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); +} + +void DirectConnectionPrivate::doLookup() +{ + Logger::debug() << "doLookup"; + emit stateChanged(QAbstractSocket::HostLookupState); + + if (SJDns::instance().isValid()) + SJDns::instance().doLookup(host_name, this, SLOT(lookupResultsReady())); + else + emit stateChanged(QAbstractSocket::UnconnectedState); +} + +void DirectConnectionPrivate::lookupResultsReady() +{ + const QJDns::Response *response = SJDns::instance().servers(host_name); + dns_records.clear(); + if (!response || !response->answerRecords.size()) { + Record record; + record.host = host_name; + dns_records << record; + } else { + foreach(const QJDns::Record &qrecord, response->answerRecords) { + Record record; + record.host = QUrl::fromAce(qrecord.name); + // may be it's a reason of connection problems of some users + if (record.host.endsWith(QLatin1Char('.'))) + record.host.chop(1); + record.port = qrecord.port; + record.weight = qrecord.weight; + record.priority = qrecord.priority; + dns_records << record; + } + } + Record &record = dns_records0; + Logger::debug() << "use:" << record.host << record.port; + socket->connectToHost(record.host, record.port); +} + +void DirectConnectionPrivate::stateChanged(QAbstractSocket::SocketState ss) +{ + Logger::debug() << ss; + if(socket_state == ss) + return; + + switch(ss) { + case QAbstractSocket::ConnectedState: { +#ifdef Q_OS_LINUX + if (qobject_cast<QTcpSocket*>(socket)) { + int fd = socket->socketDescriptor(); + Q_ASSERT(fd != -1); + Logger::debug() << "Trying to set KeepAlive attributes to socket descriptor" << fd; + if (fd != -1) { + socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); + int enableKeepAlive = 1; + Logger::debug() << setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive)); + + int maxIdle = 15; // seconds + Logger::debug() << setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle)); + + int count = 3; // send up to 3 keepalive packets out, then disconnect if no response + Logger::debug() << setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &count, sizeof(count)); + + int interval = 2; // send a keepalive packet out every 2 seconds (after the idle period) + Logger::debug() << setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(interval)); + } + } +#endif + socket_state = QAbstractSocket::ListeningState; + parent->open(); + return; + } + case QAbstractSocket::ClosingState: + parent->close(); + break; + default: + break; + } + + socket_state = ss; + emit parent->stateChanged(static_cast<Connection::SocketState>(ss)); +} + +void DirectConnectionPrivate::error(QAbstractSocket::SocketError se) +{ + socket_error = se; + emit parent->error(static_cast<Connection::SocketError>(se)); +} + DirectConnection::DirectConnection(QAbstractSocket *socket, const QString &host_name, qint16 port) : d_ptr(new DirectConnectionPrivate(host_name, port, this)) {
View file
libjreen-1.0.3.tar.bz2/src/directconnection_p.h -> libjreen-1.1.0.tar.bz2/src/directconnection_p.h
Changed
@@ -50,44 +50,11 @@ int weight; int priority; }; - DirectConnectionPrivate(const QString &hn, int p, DirectConnection *par) - : host_name(hn), port(p), dns_lookup_id(-1), parent(par) - { - do_lookup = p < 0 || !QUrl(host_name).isValid(); - socket_state = QAbstractSocket::UnconnectedState; - socket_error = QAbstractSocket::UnknownSocketError; - } - void connectSocket() - { -// QNetworkProxy proxy; -// proxy.setType(QNetworkProxy::HttpProxy); -// proxy.setHostName("proxy.istu.ru"); -// proxy.setPort(8080); -// socket->setProxy(proxy); - if (qobject_cast<QSslSocket*>(socket)) { - connect(socket, SIGNAL(encrypted()), parent, SIGNAL(connected())); - } else { - connect(socket, SIGNAL(connected()), parent, SIGNAL(connected())); - } - connect(socket, SIGNAL(disconnected()), parent, SIGNAL(disconnected())); - connect(socket, SIGNAL(readyRead()), parent, SIGNAL(readyRead())); - connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), - this, SLOT(stateChanged(QAbstractSocket::SocketState))); - connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(error(QAbstractSocket::SocketError))); - connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), - parent, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); - } - void doLookup() - { - Logger::debug() << "doLookup"; - emit stateChanged(QAbstractSocket::HostLookupState); - - if (SJDns::instance().isValid()) - SJDns::instance().doLookup(host_name, this, SLOT(lookupResultsReady())); - else - emit stateChanged(QAbstractSocket::UnconnectedState); - } + + DirectConnectionPrivate(const QString &hn, int p, DirectConnection *par); + void connectSocket(); + void doLookup(); + QAbstractSocket *socket; QString host_name; int port; @@ -97,60 +64,11 @@ int dns_lookup_id; QList<Record> dns_records; DirectConnection *parent; + public slots: - void lookupResultsReady() - { - const QJDns::Response *response = SJDns::instance().servers(host_name); - dns_records.clear(); - if(!response || !response->answerRecords.size()) { - Record record; - record.host = host_name; - dns_records << record; - } - else { - foreach(const QJDns::Record &qrecord, response->answerRecords) { - Record record; - record.host = QUrl::fromAce(qrecord.name); - // may be it's a reason of connection problems of some users - if (record.host.endsWith(QLatin1Char('.'))) - record.host.chop(1); - record.port = qrecord.port; - record.weight = qrecord.weight; - record.priority = qrecord.priority; - dns_records << record; - } - } - Record &record = dns_records0; - Logger::debug() << "use:" << record.host << record.port; - socket->connectToHost(record.host, record.port); - } - void stateChanged(QAbstractSocket::SocketState ss) - { - Logger::debug() << ss; - if(socket_state == ss) - return; - - switch(ss) { - case QAbstractSocket::ConnectedState: { - socket_state = QAbstractSocket::ListeningState; - parent->open(); - return; - } - case QAbstractSocket::ClosingState: - parent->close(); - break; - default: - break; - } - - socket_state = ss; - emit parent->stateChanged(static_cast<Connection::SocketState>(ss)); - } - void error(QAbstractSocket::SocketError se) - { - socket_error = se; - emit parent->error(static_cast<Connection::SocketError>(se)); - } + void lookupResultsReady(); + void stateChanged(QAbstractSocket::SocketState ss); + void error(QAbstractSocket::SocketError se); }; }
View file
libjreen-1.0.3.tar.bz2/src/disco.cpp -> libjreen-1.1.0.tar.bz2/src/disco.cpp
Changed
@@ -70,7 +70,7 @@ Disco::Identity identity(attributes.value(QLatin1String("category")).toString(), attributes.value(QLatin1String("type")).toString(), attributes.value(QLatin1String("name")).toString(), - attributes.value(QLatin1String("lang")).toString()); + attributes.value(QLatin1String("xml:lang")).toString()); m_identities.append(identity); } else if (name == QLatin1String("feature")) { m_features.insert(attributes.value(QLatin1String("var")).toString()); @@ -545,6 +545,11 @@ d_func()->identities.append(identity); } +void Disco::addIdentity(const QString &category, const QString &type, const QString &name, const QString &lang) +{ + d_func()->identities.append(Identity(category, type, name, lang)); +} + const QSet<QString> &Disco::features() const { Q_D(const Disco); @@ -583,6 +588,11 @@ void Disco::setSoftwareVersion(const QString &name, const QString &version, const QString &os) { + setSoftwareVersion(name, version, os, QString()); +} + +void Disco::setSoftwareVersion(const QString &name, const QString &version, const QString &os, const QString &osVersion) +{ Q_D(Disco); d->software_name = name; d->software_version = version; @@ -592,6 +602,8 @@ form->appendField(DataFormFieldHidden(QLatin1String("FORM_TYPE"), QLatin1String("urn:xmpp:dataforms:softwareinfo"))); form->appendField(DataFormFieldNone(QLatin1String("ip_version"), QStringList() << QLatin1String("ipv4") << QLatin1String("ipv6"))); form->appendField(DataFormFieldNone(QLatin1String("os"), QStringList(os))); + if (!osVersion.isEmpty()) + form->appendField(DataFormFieldNone(QLatin1String("os_version"), QStringList(osVersion))); form->appendField(DataFormFieldNone(QLatin1String("software"), QStringList(name))); form->appendField(DataFormFieldNone(QLatin1String("software_version"), QStringList(version))); d->form = form;
View file
libjreen-1.0.3.tar.bz2/src/disco.h -> libjreen-1.1.0.tar.bz2/src/disco.h
Changed
@@ -157,12 +157,14 @@ DiscoReply *requestItems(const Item &item); void addIdentity(const Identity &identity); + void addIdentity(const QString &category, const QString &type, const QString &name, const QString &lang = QString()); const IdentityList &identities() const; IdentityList &identities(); const QSet<QString> &features() const; QSet<QString> &features(); void addFeature(const QString &feature); void setSoftwareVersion(const QString &name, const QString &version, const QString &os = QString()); + void setSoftwareVersion(const QString &name, const QString &version, const QString &os, const QString &osVersion); const DataForm *form() const; void setForm(DataForm *form);
View file
libjreen-1.0.3.tar.bz2/src/disco_p.h -> libjreen-1.1.0.tar.bz2/src/disco_p.h
Changed
@@ -46,7 +46,7 @@ static DiscoPrivate *get(Disco *disco) { return disco->d_func(); } }; -class DiscoInfoFactory : public PayloadFactory<Disco::Info> +class JREEN_AUTOTEST_EXPORT DiscoInfoFactory : public PayloadFactory<Disco::Info> { public: DiscoInfoFactory(); @@ -68,7 +68,7 @@ bool m_hasDataForm; }; -class DiscoItemsFactory : public PayloadFactory<Disco::Items> +class JREEN_AUTOTEST_EXPORT DiscoItemsFactory : public PayloadFactory<Disco::Items> { public: DiscoItemsFactory();
View file
libjreen-1.0.3.tar.bz2/src/entitytimefactory_p.h -> libjreen-1.1.0.tar.bz2/src/entitytimefactory_p.h
Changed
@@ -30,7 +30,7 @@ namespace Jreen { - class EntityTimeFactory : public PayloadFactory<EntityTime> + class JREEN_AUTOTEST_EXPORT EntityTimeFactory : public PayloadFactory<EntityTime> { public: EntityTimeFactory();
View file
libjreen-1.0.3.tar.bz2/src/error.cpp -> libjreen-1.1.0.tar.bz2/src/error.cpp
Changed
@@ -59,6 +59,11 @@ return d_func()->type; } +QString Error::text(const QString &lang) const +{ + return d_func()->text.value(lang); +} + Error::Condition Error::condition() const { return d_func()->condition;
View file
libjreen-1.0.3.tar.bz2/src/error.h -> libjreen-1.1.0.tar.bz2/src/error.h
Changed
@@ -161,6 +161,7 @@ ~Error(); Type type() const; + QString text(const QString &lang = QString()) const; Condition condition() const; QString conditionText() const; private:
View file
libjreen-1.0.3.tar.bz2/src/errorfactory.cpp -> libjreen-1.1.0.tar.bz2/src/errorfactory.cpp
Changed
@@ -68,7 +68,7 @@ Payload::Ptr ErrorFactory::createPayload() { - return Payload::Ptr(new Error(m_type,m_condition)); + return Payload::Ptr(new Error(m_type, m_condition, LangMap(m_text))); } QStringList ErrorFactory::features() const @@ -83,6 +83,7 @@ if (m_depth == 1) { QStringRef subtype = attributes.value(QLatin1String("type")); m_type = strToEnum<Error::Type>(subtype,error_types); + m_text.clear(); } else if(m_depth == 2) { if(name == QLatin1String("text")) m_state = AtText; @@ -95,7 +96,8 @@ void ErrorFactory::handleCharacterData(const QStringRef& text) { - Q_UNUSED(text); + if (m_state == AtText) + m_text = text.toString(); } void ErrorFactory::handleEndElement(const QStringRef& name, const QStringRef& uri) {
View file
libjreen-1.0.3.tar.bz2/src/errorfactory_p.h -> libjreen-1.1.0.tar.bz2/src/errorfactory_p.h
Changed
@@ -30,7 +30,7 @@ namespace Jreen { -class ErrorFactory : public PayloadFactory<Error> +class JREEN_AUTOTEST_EXPORT ErrorFactory : public PayloadFactory<Error> { public: ErrorFactory(); @@ -46,6 +46,7 @@ enum State {AtCondition,AtText}; State m_state; int m_depth; + QString m_text; Error::Type m_type; Error::Condition m_condition; };
View file
libjreen-1.1.0.tar.bz2/src/experimental
Added
+(directory)
View file
libjreen-1.1.0.tar.bz2/src/experimental/iristransport.cpp
Added
@@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "iristransport.h" + +namespace Jreen +{ +namespace JingleIce +{ + +} // namespace JingleIce +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/experimental/iristransport.h
Added
@@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_JINGLEICE_IRISTRANSPORT_H +#define JREEN_JINGLEICE_IRISTRANSPORT_H + +#include "jingletransport.h" +#include "3rdparty/icesupport/ice176.h" +#include "3rdparty/icesupport/udpportreserver.h" + +namespace Jreen +{ +namespace JingleIce +{ + +} // namespace JingleIce +} // namespace Jreen + +#endif // JREEN_JINGLEICE_IRISTRANSPORT_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingle.cpp
Added
@@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "jingle_p.h" +#include "jinglesession_p.h" +#include "../iqreply.h" + +namespace Jreen +{ + +Jingle::Jingle() : action(Jingle::SessionInitiate) +{ +} + +Jingle::Ptr Jingle::create(JingleSession *session, Action action) +{ + Jingle::Ptr jingle = Jingle::Ptr::create(); + JingleSessionPrivate *d = JingleSessionPrivate::get(session); + jingle->initiator = d->client->jid(); +// jingle->responder = d->other; + if (d->incoming) + qSwap(jingle->initiator, jingle->responder); + jingle->action = action; + jingle->sid = d->sid; + return jingle; +} + +IQReply *Jingle::send(JingleSession *session, Action action, const QList<Content> &contents) +{ + JingleSessionPrivate *d = JingleSessionPrivate::get(session); + Jingle::Ptr jingle = create(session, action); + jingle->contents = contents; + IQ iq(IQ::Set, d->other); + iq.addExtension(jingle); + return d->client->send(iq); +} + +IQReply *Jingle::send(JingleSession *session, Action action, const Content &content) +{ + return send(session, action, QList<Content>() << content); +} + +IQReply *Jingle::send(JingleSession *session, Action action, JingleContent *contentObject) +{ + JingleSessionPrivate *d = JingleSessionPrivate::get(session); + JingleSessionContent *content = d->findContent(contentObject); + Q_ASSERT(content); + return send(session, action, *content); +} + +}
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingle_p.h
Added
@@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLE_H +#define JINGLE_H + +#include "../stanzaextension.h" +#include "../jid.h" +#include "jingletransport.h" +#include "jinglecontent.h" + +namespace Jreen +{ + +class IQReply; + +class Jingle : public Payload +{ + J_PAYLOAD(Jreen::Jingle) +public: + enum Action { + ContentAccept, + ContentAdd, + ContentModify, + ContentReject, + ContentRemove, + DescriptionInfo, + SecurityInfo, + SessionAccept, + SessionInfo, + SessionInitiate, + SessionTerminate, + TransportAccept, + TransportInfo, + TransportReject, + TransportReplace + }; + + enum CreatorType { + Invalid = -1, + None = 0, + Initiator = 1, + Responder = 2, + Both = Initiator | Responder + }; + + typedef QFlags<CreatorType> SendersType; + + struct Content + { + Content() : creator(Initiator), senders(Both) {} + QString name; + CreatorType creator; + SendersType senders; + JingleDescription::Ptr description; + QList<JingleTransportInfo::Ptr> transports; + }; + + Jingle(); + + static Jingle::Ptr create(JingleSession *session, Action action); + static IQReply *send(JingleSession *session, Action action, const QList<Content> &contents = QList<Content>()); + template <typename T> + static IQReply *send(JingleSession *session, Action action, const QList<T> &list) + { + QList<Content> contents; + for (int i = 0; i < list.size(); ++i) + contents << listi; + return send(session, action, contents); + } + + static IQReply *send(JingleSession *session, Action action, const Content &content); + static IQReply *send(JingleSession *session, Action action, JingleContent *content); + + JID initiator; + JID responder; + QString sid; + Action action; + QList<Content> contents; +}; + +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(Jreen::Jingle::SendersType) + +#endif // JINGLE_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingleaudiocontent.cpp
Added
@@ -0,0 +1,281 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "jingleaudiocontent_p.h" +#include "jinglespeexcodec_p.h" +#include <QSet> +#include <QtEndian> +#include <QDateTime> +#include <QDebug> +#include <qmath.h> + +namespace Jreen +{ + +enum { JingleRTP = 0, JingleRTCP = 1 }; + +class JingleRtpHeader +{ +public: + JingleRtpHeader() : begin(2 << 6), pt(0), sq(0), ts(0), ssrc(0) {} + JingleRtpHeader(const char * &data, int &len); + enum { Version = 2 }; + + bool isValid() const { return version() == 2; } + quint8 version() const { return begin >> 6; } + bool hasPadding() const { return begin & (1 << 5); } + bool hasExtension() const { return begin & (1 << 4); } + quint8 csrcCount() const { return begin & 0x7; } + bool hasMarker() const { return begin & (1 << 7); } + quint8 payloadType() const { return pt /*& 0xef*/ ; } + void setPayloadType(quint8 type) { /* pt &= ~0xef; pt |= type;*/ pt = type; } + quint16 sequence() const { return sq; } + void setSequence(quint16 seq) { sq = seq; } + quint32 timestamp() const { return ts; } + void setTimestamp(quint32 timest) { ts = timest; } + quint32 synchronizationSource() const { return ssrc; } + QByteArray data() const; + +private: + quint8 begin; + quint8 pt; + quint16 sq; + quint32 ts; + quint32 ssrc; +}; + +JingleRtpHeader::JingleRtpHeader(const char * &xdata, int &len) +{ + const uchar * &udata = reinterpret_cast<const uchar * &>(xdata); + const uchar *start = udata; + begin = udata0; + pt = udata1; + sq = qFromBigEndian<quint16>(udata + 2); + ts = qFromBigEndian<quint32>(udata + 4); + ssrc = qFromBigEndian<quint32>(udata + 4); + udata += 12; + udata += csrcCount() * 4; + len -= (udata - start); +} + +QByteArray JingleRtpHeader::data() const +{ + QByteArray result(1 + 1 + 2 + 4 + 4, Qt::Uninitialized); + uchar *d = reinterpret_cast<uchar*>(result.data()); + d0 = begin; + d1 = pt; + qToBigEndian(sq, d + 2); + qToBigEndian(ts, d + 4); + qToBigEndian(ssrc, d + 8); + return result; +} + +JingleAudioDevice::JingleAudioDevice(JingleAudioContentPrivate *content) + : m_content(content) +{ +} + +JingleAudioDevice::~JingleAudioDevice() +{ +} + +bool JingleAudioDevice::open(OpenMode mode) +{ + Q_UNUSED(mode); + return QIODevice::open(QIODevice::ReadWrite | QIODevice::Unbuffered); +} + +void JingleAudioDevice::close() +{ + m_buffer.clear(); + m_outputBuffer.clear(); + QIODevice::close(); +} + +bool JingleAudioDevice::isSequential() const +{ + return true; +} + +qint64 JingleAudioDevice::bytesAvailable() const +{ + return m_outputBuffer.size(); +} + +void JingleAudioDevice::appendData(const QByteArray &data) +{ + m_outputBuffer.append(data); + if (m_outputBuffer.size() > (8 * 320)) + m_outputBuffer.remove(0, m_outputBuffer.size() - 8 * 320); + emit readyRead(); +} + +qint64 JingleAudioDevice::readData(char *data, qint64 maxSize) +{ + qMemSet(data, 0, maxSize); + qint64 size = qMin<qint64>(m_outputBuffer.size(), maxSize); + qMemCopy(data, m_outputBuffer.data(), size); + m_outputBuffer.remove(0, size); + return maxSize; +} + +qint64 JingleAudioDevice::writeData(const char *data, qint64 len) +{ + m_buffer.append(data, len); + const JingleAudioPayload &payload = m_content->payloads.first(); + JingleAudioCodec *codec = m_content->codecs.value(payload.id()); + // We use only two-byte integers right now + const int frameSize = codec->frameSize() * 2; + int offset = 0; + while (m_buffer.size() - offset >= frameSize) { + m_content->send(payload.id(), codec->encodeFrame(m_buffer.data() + offset, frameSize)); + offset += frameSize; + } + m_buffer.remove(0, offset); + return len; +} + +static inline void init_factories(QList<JingleAudioCodecFactory*> &factories) +{ + Q_UNUSED(factories); +#ifdef JREEN_HAVE_SPEEX + factories << new JingleSpeexCodecFactory; +#endif +} + +Q_GLOBAL_STATIC_WITH_INITIALIZER(QList<JingleAudioCodecFactory*>, factories, init_factories(*x)) + +JingleAudioContent::JingleAudioContent(JingleSession *session) + : JingleContent(session, *new JingleAudioContentPrivate(this)) +{ + Q_D(JingleAudioContent); + d->device.reset(new JingleAudioDevice(d)); + setComponentCount(2); +} + +JingleAudioContent::~JingleAudioContent() +{ + qDeleteAll(d_func()->codecs); +} + +JingleAudioPayload JingleAudioContent::currentPayload() const +{ + return d_func()->payloads.value(0); +} + +int JingleAudioContent::currentPayloadFrameSize() const +{ + Q_D(const JingleAudioContent); + int id = d->payloads.value(0).id(); + JingleAudioCodec *codec = d->codecs.value(id); + return codec ? codec->frameSize() : -1; +} + +QIODevice *JingleAudioContent::audioDevice() const +{ + return d_func()->device.data(); +} + +JingleDescription::Ptr JingleAudioContent::defaultDescription() +{ + JingleAudioDescription::Ptr info = JingleAudioDescription::Ptr::create(); + foreach (JingleAudioCodecFactory *factory, *factories()) + info->payloads << factory->supportedPayloads(); + return info; +} + +JingleDescription::Ptr JingleAudioContent::handleDescription(const JingleDescription::Ptr &description) +{ + Q_D(JingleAudioContent); + JingleAudioDescription::Ptr info = description.staticCast<JingleAudioDescription>(); + QSet<int> payloads; + foreach (JingleAudioCodecFactory *factory, *factories()) { + for (int i = 0; i < info->payloads.size(); ++i) { + if (payloads.contains(i)) + continue; + const JingleAudioPayload &payload = info->payloads.at(i); + if (factory->supportsPayload(payload)) { + d->payloads << payload; + JingleAudioCodec *codec = factory->createCodec(payload); + d->codecs.insert(payload.id(), codec); + payloads.insert(i); + } + } + } + if (d->payloads.isEmpty()) + return JingleDescription::Ptr(); + JingleAudioDescription::Ptr result = JingleAudioDescription::Ptr::create(); + result->payloads = d->payloads; + if (!d->payloads.isEmpty()) + emit payloadChoosed(d->payloads.value(0)); + return result; +} + +void JingleAudioContent::registerCodec(JingleAudioCodecFactory *factory) +{ + factories()->append(factory); +} + +void JingleAudioContentPrivate::_q_stateChanged(Jreen::JingleTransport::State newState) +{ + if (newState == JingleTransport::Connected) + device->open(QIODevice::ReadWrite); + JingleContentPrivate::_q_stateChanged(newState); +} + +void JingleAudioContentPrivate::send(int payload, const QByteArray &data) +{ + JingleRtpHeader header; + header.setSequence(sequence++); + header.setTimestamp(QDateTime::currentDateTime().toTime_t()); + header.setPayloadType(payload); + QByteArray result = header.data(); + result += data; + q_func()->send(JingleRTP, result); +} + +void JingleAudioContent::receive(int component, const QByteArray &receivedData) +{ + if (component == JingleRTCP) { + qDebug() << Q_FUNC_INFO << receivedData.toHex(); + } + if (component != JingleRTP) + return; + Q_D(JingleAudioContent); + const char *data = receivedData.constData(); + int size = receivedData.size(); + JingleRtpHeader header(data, size); + if (!header.isValid()) + return; + JingleAudioCodec *codec = d->codecs.value(header.payloadType()); + if (!codec) + return; + QByteArray audio = codec->decodeFrame(data, size); + d->device->appendData(audio); +} + +} + +#include "moc_jingleaudiocontent.cpp"
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingleaudiocontent.h
Added
@@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLEAUDIOCONTENT_H +#define JINGLEAUDIOCONTENT_H + +#include "jinglecontent.h" +#include "jingleaudiopayload.h" + +namespace Jreen +{ + +class JingleAudioContentPrivate; +class JingleAudioCodecFactory; + +class JREEN_EXPORT JingleAudioContent : public JingleContent +{ + Q_OBJECT + Q_DECLARE_PRIVATE(JingleAudioContent) +public: + JingleAudioContent(JingleSession *session); + ~JingleAudioContent(); + + JingleAudioPayload currentPayload() const; + int currentPayloadFrameSize() const; + QIODevice *audioDevice() const; + + virtual JingleDescription::Ptr defaultDescription(); + virtual JingleDescription::Ptr handleDescription(const JingleDescription::Ptr &description); + + static void registerCodec(JingleAudioCodecFactory *factory); + +protected: + virtual void receive(int component, const QByteArray &data); + +signals: + void payloadChoosed(const Jreen::JingleAudioPayload &payload); +}; + +class JREEN_EXPORT JingleAudioCodec +{ +public: + virtual ~JingleAudioCodec() {} + + virtual int frameSize() const = 0; + virtual QByteArray encodeFrame(const char *data, int size) = 0; + virtual QByteArray decodeFrame(const char *data, int size) = 0; +}; + +class JREEN_EXPORT JingleAudioCodecFactory +{ +public: + virtual ~JingleAudioCodecFactory() {} + virtual QList<JingleAudioPayload> supportedPayloads() = 0; + virtual bool supportsPayload(const JingleAudioPayload &payload) = 0; + virtual JingleAudioCodec *createCodec(const JingleAudioPayload &payload) = 0; +}; + +} + +Q_DECLARE_INTERFACE(Jreen::JingleAudioCodecFactory, "org.qutim.Jreen.Jingle.AudioCodecFactory") + +#endif // JINGLEAUDIOCONTENT_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingleaudiocontent_p.h
Added
@@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLEAUDIOCONTENT_P_H +#define JINGLEAUDIOCONTENT_P_H + +#include "jingleaudiocontent.h" +#include "jingleaudiopayload_p.h" +#include "jinglecontent_p.h" + +namespace Jreen +{ + +class JingleAudioDevice : public QIODevice +{ +public: + JingleAudioDevice(JingleAudioContentPrivate *content); + ~JingleAudioDevice(); + + virtual bool open(OpenMode mode); + virtual void close(); + bool isSequential() const; + qint64 bytesAvailable() const; + void appendData(const QByteArray &data); + +protected: + virtual qint64 readData(char *data, qint64 len); + virtual qint64 writeData(const char *data, qint64 len); + +private: + JingleAudioContentPrivate *m_content; + QByteArray m_buffer; + QByteArray m_outputBuffer; +}; + +class JingleAudioContentPrivate : public JingleContentPrivate +{ + Q_DECLARE_PUBLIC(JingleAudioContent) +public: + JingleAudioContentPrivate(JingleAudioContent *q) + : JingleContentPrivate(q), sequence(qrand()), lastSequence(0) {} + + quint16 sequence; + quint16 lastSequence; + QScopedPointer<JingleAudioDevice> device; + QList<JingleAudioPayload> payloads; + QMap<int, JingleAudioCodec*> codecs; + + void _q_stateChanged(Jreen::JingleTransport::State); + void send(int payload, const QByteArray &data); + static JingleAudioContentPrivate *get(JingleAudioContent *q) { return q->d_func(); } +}; + +class JingleAudioDescription : public JingleDescription +{ + J_PAYLOAD(Jreen::JingleAudioDescription) +public: + QList<JingleAudioPayload> payloads; +}; + +} + +#endif // JINGLEAUDIOCONTENT_P_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingleaudiocontentfactory.cpp
Added
@@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "jingleaudiocontentfactory_p.h" + +#define NS_RTP QLatin1String("urn:xmpp:jingle:apps:rtp:1") +#define NS_RTP_AUDIO QLatin1String("urn:xmpp:jingle:apps:rtp:audio") + +namespace Jreen +{ + +JingleAudioContentFactory::JingleAudioContentFactory() + : JingleContentFactory<JingleAudioDescription>(NS_RTP, QLatin1String("audio")), m_state(AtRoot), m_depth(0) +{ +} + +JingleContent *JingleAudioContentFactory::createObject(JingleSession *session) +{ + return new JingleAudioContent(session); +} + +QStringList JingleAudioContentFactory::features() const +{ + return QStringList(m_elementUri) + << NS_RTP_AUDIO; +} + +void JingleAudioContentFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(name); + Q_UNUSED(uri); + m_depth++; + if (m_depth == 1) { + m_info = JingleAudioDescription::Ptr::create(); + } if (m_depth == 2 && name == QLatin1String("payload-type")) { + m_state = AtPayload; + m_payload.reset(new JingleAudioPayload); + m_payload->setId(attributes.value(QLatin1String("id")).toString().toInt()); + m_payload->setChannelCount(attributes.value(QLatin1String("channels")).toString().toInt()); + m_payload->setClockRate(attributes.value(QLatin1String("clockrate")).toString().toInt()); + m_payload->setName(attributes.value(QLatin1String("name")).toString()); + m_payload->setMaximumPacketTime(attributes.value(QLatin1String("maxptime")).toString().toInt()); + m_payload->setPacketTime(attributes.value(QLatin1String("ptime")).toString().toInt()); + } else if (m_depth == 3 && name == QLatin1String("parameter")) { + m_payload->setParameter(attributes.value(QLatin1String("name")).toString(), + attributes.value(QLatin1String("value")).toString()); + } +} + +void JingleAudioContentFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + Q_UNUSED(name); + Q_UNUSED(uri); + if (m_state == AtPayload && m_depth == 2) { + m_state = AtRoot; + m_info->payloads << *m_payload; + m_payload.reset(); + } + m_depth--; +} + +void JingleAudioContentFactory::handleCharacterData(const QStringRef &text) +{ + Q_UNUSED(text); +} + +void JingleAudioContentFactory::serialize(Payload *obj, QXmlStreamWriter *writer) +{ + JingleAudioDescription *info = se_cast<JingleAudioDescription*>(obj); + Q_ASSERT(info); + + writer->writeStartElement(QLatin1String("description")); + writer->writeDefaultNamespace(m_elementUri); + writer->writeAttribute(QLatin1String("media"), m_media); + foreach (const JingleAudioPayload &payload, info->payloads) { + const JingleAudioPayloadData *d = JingleAudioPayloadData::get(payload); + writer->writeStartElement(QLatin1String("payload-type")); + writer->writeAttribute(QLatin1String("id"), QString::number(d->id)); + if (d->channelCount > 0) + writer->writeAttribute(QLatin1String("channels"), QString::number(d->channelCount)); + if (d->clockRate > 0) + writer->writeAttribute(QLatin1String("clockrate"), QString::number(d->clockRate)); + if (!d->name.isEmpty()) + writer->writeAttribute(QLatin1String("name"), d->name); + if (d->maxmimumPacketTime > 0) + writer->writeAttribute(QLatin1String("maxptime"), QString::number(d->maxmimumPacketTime)); + if (d->packetTime > 0) + writer->writeAttribute(QLatin1String("ptime"), QString::number(d->packetTime)); + QMapIterator<QString, QString> it(d->parameters); + while (it.hasNext()) { + it.next(); + writer->writeEmptyElement(QLatin1String("parameter")); + writer->writeAttribute(QLatin1String("name"), it.key()); + writer->writeAttribute(QLatin1String("value"), it.value()); + } + writer->writeEndElement(); + } + writer->writeEndElement(); +} + +Payload::Ptr JingleAudioContentFactory::createPayload() +{ + Payload::Ptr result = m_info; + m_info.clear(); + return result; +} + +}
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingleaudiocontentfactory_p.h
Added
@@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLEAUDIOCONTENTFACTORY_P_H +#define JINGLEAUDIOCONTENTFACTORY_P_H + +#include "jingleaudiocontent_p.h" +#include "jingleaudiopayload.h" + +namespace Jreen +{ + +class JingleAudioContentFactory : public JingleContentFactory<JingleAudioDescription> +{ +public: + JingleAudioContentFactory(); + + virtual JingleContent *createObject(JingleSession *session); + virtual QStringList features() const; + virtual void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + virtual void handleEndElement(const QStringRef &name, const QStringRef &uri); + virtual void handleCharacterData(const QStringRef &text); + virtual void serialize(Payload *obj, QXmlStreamWriter *writer); + virtual Payload::Ptr createPayload(); +private: + enum State { AtRoot, AtPayload } m_state; + int m_depth; + JingleAudioDescription::Ptr m_info; + QScopedPointer<JingleAudioPayload> m_payload; +}; + +} + +#endif // JINGLEAUDIOCONTENTFACTORY_P_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingleaudiopayload.cpp
Added
@@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "jingleaudiopayload_p.h" + +namespace Jreen +{ + +Q_GLOBAL_STATIC_WITH_ARGS(QSharedDataPointer<JingleAudioPayloadData>, nullData, (new JingleAudioPayloadData)) + +JingleAudioPayload::JingleAudioPayload() : d(*nullData()) +{ +} + +JingleAudioPayload::JingleAudioPayload(const JingleAudioPayload &o) : d(o.d) +{ +} + +JingleAudioPayload &JingleAudioPayload::operator =(const JingleAudioPayload &o) +{ + d = o.d; + return *this; +} + +JingleAudioPayload::~JingleAudioPayload() +{ +} + +bool JingleAudioPayload::operator ==(const JingleAudioPayload &o) +{ + return (o.id() < 96 && d->id == o.id()) + || (d->channelCount == o.channelCount() + && d->clockRate == o.clockRate() + && d->name == o.name()); +} + +bool JingleAudioPayload::operator !=(const JingleAudioPayload &o) +{ + return !operator ==(o); +} + +int JingleAudioPayload::channelCount() const +{ + return d->channelCount; +} + +void JingleAudioPayload::setChannelCount(int channelCount) +{ + d->channelCount = (channelCount <= 0 ? 1 : channelCount); +} + +int JingleAudioPayload::clockRate() const +{ + return d->clockRate; +} + +void JingleAudioPayload::setClockRate(int clockRate) +{ + d->clockRate = (clockRate <= 0 ? -1 : clockRate); +} + +int JingleAudioPayload::id() const +{ + return d->id; +} + +void JingleAudioPayload::setId(int id) +{ + d->id = id; +} + +int JingleAudioPayload::maximumPacketTime() const +{ + return d->maxmimumPacketTime; +} + +void JingleAudioPayload::setMaximumPacketTime(int maximumPacketTime) +{ + d->maxmimumPacketTime = (maximumPacketTime <= 0 ? -1 : maximumPacketTime); +} + +QString JingleAudioPayload::name() const +{ + return d->name; +} + +void JingleAudioPayload::setName(const QString &name) +{ + d->name = name; +} + +int JingleAudioPayload::packetTime() const +{ + return d->packetTime; +} + +void JingleAudioPayload::setPacketTime(int packetTime) +{ + d->packetTime = (packetTime <= 0 ? -1 : packetTime); +} + +QString JingleAudioPayload::parameter(const QString &name) const +{ + return d->parameters.value(name); +} + +void JingleAudioPayload::setParameter(const QString &name, const QString &value) +{ + d->parameters.insert(name, value); +} + +}
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingleaudiopayload.h
Added
@@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLEAUDIOPAYLOAD_H +#define JINGLEAUDIOPAYLOAD_H + +#include "../jreen.h" +#include <QSharedDataPointer> + +namespace Jreen +{ + +class JingleAudioPayloadData; + +class JREEN_EXPORT JingleAudioPayload +{ +public: + JingleAudioPayload(); + JingleAudioPayload(const JingleAudioPayload &o); + JingleAudioPayload &operator =(const JingleAudioPayload &o); + ~JingleAudioPayload(); + + bool operator ==(const JingleAudioPayload &o); + bool operator !=(const JingleAudioPayload &o); + + int channelCount() const; + void setChannelCount(int channelCount); + int clockRate() const; + void setClockRate(int clockRate); + int id() const; + void setId(int id); + int maximumPacketTime() const; + void setMaximumPacketTime(int maximumPacketTime); + QString name() const; + void setName(const QString &name); + int packetTime() const; + void setPacketTime(int packetTime); + QString parameter(const QString &name) const; + void setParameter(const QString &name, const QString &value); + +private: + QSharedDataPointer<JingleAudioPayloadData> d; + friend class JingleAudioPayloadData; +}; + +} + +#endif // JINGLEAUDIOPAYLOAD_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingleaudiopayload_p.h
Added
@@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLEAUDIOPAYLOAD_P_H +#define JINGLEAUDIOPAYLOAD_P_H + +#include "jingleaudiopayload.h" +#include <QMap> + +namespace Jreen +{ + +class JingleAudioPayloadData : public QSharedData +{ +public: + JingleAudioPayloadData() + : channelCount(1), clockRate(-1), id(-1), maxmimumPacketTime(-1), packetTime(-1) {} + JingleAudioPayloadData(const JingleAudioPayloadData &o) + : QSharedData(o), channelCount(o.channelCount), clockRate(o.clockRate), id(o.id), + maxmimumPacketTime(o.maxmimumPacketTime), packetTime(o.packetTime), + name(o.name), parameters(o.parameters) {} + int channelCount; + int clockRate; + int id; + int maxmimumPacketTime; + int packetTime; + QString name; + QMap<QString, QString> parameters; + + static const JingleAudioPayloadData *get(const JingleAudioPayload &p) { return p.d.constData(); } +}; + +} + +#endif // JINGLEAUDIOPAYLOAD_P_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglecontent.cpp
Added
@@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "jinglecontent_p.h" +#include "jingletransport.h" +#include "jinglesession_p.h" +#include <QDebug> + +namespace Jreen +{ + +void JingleContentPrivate::_q_received(int component, const QByteArray &data) +{ + q_func()->receive(component, data); +} + +void JingleContentPrivate::_q_stateChanged(Jreen::JingleTransport::State newState) +{ + state = static_cast<JingleContent::State>(newState); + emit q_func()->stateChanged(state); +} + +void JingleContentPrivate::_q_localInfoReady(const Jreen::JingleTransportInfo::Ptr &) +{ + if (needTransports > 0) { + needTransports--; + if (needTransports == 0) { + JingleSessionPrivate *sessionD = JingleSessionPrivate::get(session); + sessionD->onTransportsReady(q_func(), transports); + } + } else { + canAccept = 1; + transportInfos.clear(); + transport = qobject_cast<JingleTransport*>(q_func()->sender()); + Q_ASSERT(transport); + transports << transport; + accept(); + } +} + +void JingleContentPrivate::_q_tryStateChanged(Jreen::JingleTransport::State state) +{ + if (state == JingleTransport::Failed) { + JingleTransport *transport = qobject_cast<JingleTransport*>(q_func()->sender()); + Q_ASSERT(transport); + delete transport; + tryNextTransport(); + } +} + +void JingleContentPrivate::setTransport(JingleTransport *trueTransport) +{ + transport = trueTransport; + qDebug() << Q_FUNC_INFO << transport; + QObject::connect(transport, SIGNAL(received(int,QByteArray)), + q_func(), SLOT(_q_received(int,QByteArray))); + QObject::connect(transport, SIGNAL(stateChanged(Jreen::JingleTransport::State)), + q_func(), SLOT(_q_stateChanged(Jreen::JingleTransport::State))); +} + +void JingleContentPrivate::initiateTransports() +{ + JingleSessionPrivate *sessionD = JingleSessionPrivate::get(session); + JingleManagerPrivate *manager = JingleManagerPrivate::get(sessionD->client->jingleManager()); + foreach (AbstractJingleTransportFactory *factory, manager->transports) { + JingleTransport *transport = factory->createObject(q_func()); + if (transport->localInfo().isNull()) { + QObject::connect(transport, SIGNAL(localInfoReady(Jreen::JingleTransportInfo::Ptr)), + q_func(), SLOT(_q_localInfoReady(Jreen::JingleTransportInfo::Ptr))); + needTransports++; + } + transports << transport; + } +} + +void JingleContentPrivate::accept() +{ + if (needAccept || !canAccept) + return; + JingleSessionPrivate *sessionD = JingleSessionPrivate::get(session); + sessionD->onTransportsReady(q_func(), transports); +} + +void JingleContentPrivate::decline() +{ + IQReply *reply = Jingle::send(session, Jingle::ContentReject, q_func()); + Q_UNUSED(reply); +} + +void JingleContentPrivate::tryNextTransport() +{ + JingleSessionPrivate *sessionD = JingleSessionPrivate::get(session); + JingleManagerPrivate *manager = JingleManagerPrivate::get(sessionD->client->jingleManager()); + JingleTransport *transport = 0; + JingleTransportInfo::Ptr info; + while (!transport && !transportInfos.isEmpty()) { + info = transportInfos.takeFirst(); + transport = manager->transport(info, q_func()); + } + if (!transport) { + q_func()->decline(); + return; + } + transport->setRemoteInfo(info, false); + QObject::connect(transport, SIGNAL(localInfoReady(Jreen::JingleTransportInfo::Ptr)), + q_func(), SLOT(_q_localInfoReady(Jreen::JingleTransportInfo::Ptr))); + QObject::connect(transport, SIGNAL(stateChanged(Jreen::JingleTransport::State)), + q_func(), SLOT(_q_stateChanged(Jreen::JingleTransport::State))); +} + +void JingleContentPrivate::initiateTransports(const QList<JingleTransportInfo::Ptr> &transportInfosOther) +{ + transportInfos = transportInfosOther; + tryNextTransport(); +} + +JingleContent::JingleContent(JingleSession *session) + : QObject(session), d_ptr(new JingleContentPrivate(this)) +{ + Q_D(JingleContent); + d->session = session; +} + +JingleContent::JingleContent(JingleSession *session, JingleContentPrivate &p) + : QObject(session), d_ptr(&p) +{ + Q_D(JingleContent); + d->session = session; +} + +JingleContent::~JingleContent() +{ +} + +JingleSession *JingleContent::session() const +{ + return d_func()->session; +} + +JingleContent::State JingleContent::state() const +{ + return d_func()->state; +} + +bool JingleContent::isAcceptable() const +{ + return d_func()->needAccept; +} + +void JingleContent::accept() +{ + Q_D(JingleContent); + d->needAccept = false; + d->accept(); +} + +void JingleContent::decline() +{ + Q_D(JingleContent); + if (d->needAccept) { + d->needAccept = false; + IQReply *reply = Jingle::send(d->session, Jingle::ContentReject, this); + Q_UNUSED(reply); + } +} + +int JingleContent::componentCount() const +{ + return d_func()->componentCount; +} + +void JingleContent::setComponentCount(int count) +{ + d_func()->componentCount = count; +} + +void JingleContent::send(int component, const QByteArray &data) +{ + Q_D(JingleContent); + if (d->transport) + d->transport->send(component, data); +} + +void JingleContent::send(int component, const char *data, int size) +{ + send(component, QByteArray(data, size)); +} + +} + +#include "moc_jinglecontent.cpp"
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglecontent.h
Added
@@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLECONTENT_H +#define JINGLECONTENT_H + +#include "../stanzaextension.h" +#include "jingletransport.h" +#include <QStringList> + +namespace Jreen +{ + +class JingleSession; +class JingleContentPrivate; + +typedef Payload JingleDescription; + +class JREEN_EXPORT JingleContent : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(JingleContent) + Q_PROPERTY(Jreen::JingleContent::State state READ state NOTIFY stateChanged) +public: + enum State { + Disconnected, + Gathering, + Connecting, + Connected, + Failed + }; + + JingleContent(JingleSession *session); + ~JingleContent(); + + JingleSession *session() const; + int componentCount() const; + virtual JingleDescription::Ptr defaultDescription() = 0; + virtual JingleDescription::Ptr handleDescription(const JingleDescription::Ptr &description) = 0; + State state() const; + bool isAcceptable() const; + void accept(); + void decline(); + +signals: + void stateChanged(Jreen::JingleContent::State); + +protected: + JingleContent(JingleSession *session, JingleContentPrivate &p); + void setComponentCount(int count); + void send(int component, const QByteArray &data); + void send(int component, const char *data, int size); + virtual void receive(int component, const QByteArray &data) = 0; + Q_PRIVATE_SLOT(d_func(), void _q_received(int, const QByteArray &)) + Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(Jreen::JingleTransport::State)) + Q_PRIVATE_SLOT(d_func(), void _q_localInfoReady(const Jreen::JingleTransportInfo::Ptr &)) + + QScopedPointer<JingleContentPrivate> d_ptr; +}; + +class JREEN_EXPORT AbstractJingleContentFactory : public AbstractPayloadFactory +{ +public: + inline JingleDescription::Ptr createDescription() { return createPayload(); } + virtual QString media() const = 0; + virtual JingleContent *createObject(JingleSession *session) = 0; +}; + +template <typename Extension> +class JingleContentFactory : public AbstractJingleContentFactory +{ +public: + JingleContentFactory(const QString &uri, const QString &media = QString()); + virtual ~JingleContentFactory(); + + virtual QString media() const; + virtual int payloadType() const; + virtual QStringList features() const; + virtual bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + +protected: + const QString m_elementUri; + const QString m_media; +}; + +template <typename Extension> +Q_INLINE_TEMPLATE JingleContentFactory<Extension>::JingleContentFactory(const QString &uri, const QString &media) + : m_elementUri(uri), m_media(media) +{ +} + +template <typename Extension> +Q_INLINE_TEMPLATE JingleContentFactory<Extension>::~JingleContentFactory() +{ +} + +template <typename Extension> +Q_INLINE_TEMPLATE QString JingleContentFactory<Extension>::media() const +{ + return m_media; +} + +template <typename Extension> +Q_INLINE_TEMPLATE int JingleContentFactory<Extension>::payloadType() const +{ + return Extension::staticPayloadType(); +} + +template <typename Extension> +Q_INLINE_TEMPLATE QStringList JingleContentFactory<Extension>::features() const +{ + return QStringList(m_elementUri); +} + +template <typename Extension> +Q_INLINE_TEMPLATE bool JingleContentFactory<Extension>::canParse(const QStringRef &name, const QStringRef &uri, + const QXmlStreamAttributes &attributes) +{ + return name == QLatin1String("description") && uri == m_elementUri + && (m_media.isEmpty() || attributes.value(QLatin1String("media")) == m_media); +} + +} + +#endif // JINGLECONTENT_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglecontent_p.h
Added
@@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLECONTENT_P_H +#define JINGLECONTENT_P_H + +#include "jinglecontent.h" + +namespace Jreen +{ + +class JingleContentPrivate +{ + Q_DECLARE_PUBLIC(JingleContent) +public: + JingleContentPrivate(JingleContent *q) + : q_ptr(q), transport(0), componentCount(1), needTransports(0), + needAccept(0), canAccept(0), state(JingleContent::Gathering) {} + + JingleContent *q_ptr; + JingleSession *session; + JingleTransport *transport; + int componentCount : 14; + int needTransports : 14; + int needAccept : 1; + int canAccept : 1; + JingleContent::State state; + QList<JingleTransport*> transports; + QList<JingleTransportInfo::Ptr> transportInfos; + + void _q_received(int component, const QByteArray &data); + virtual void _q_stateChanged(Jreen::JingleTransport::State); + void _q_localInfoReady(const Jreen::JingleTransportInfo::Ptr &); + void _q_tryStateChanged(Jreen::JingleTransport::State state); + void setTransport(JingleTransport *trueTransport); + void initiateTransports(); + void tryNextTransport(); + void initiateTransports(const QList<JingleTransportInfo::Ptr> &transportInfos); + void accept(); + void decline(); + static JingleContentPrivate *get(JingleContent *q) { return q->d_func(); } +}; + +} + +#endif // JINGLECONTENT_P_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglefactory.cpp
Added
@@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "jinglefactory_p.h" +#include "../jstrings.h" +#include "../client_p.h" + +#define NS_JINGLE QLatin1String("urn:xmpp:jingle:1") +#define NS_JINGLE_RTP QLatin1String("urn:xmpp:jingle:apps:rtp:1") + +namespace Jreen +{ + +static const char *actions = { + "content-accept", + "content-add", + "content-modify", + "content-reject", + "content-remove", + "description-info", + "security-info", + "session-accept", + "session-info", + "session-initiate", + "session-terminate", + "transport-accept", + "transport-info", + "transport-reject", + "transport-replace" +}; + +static const char *senders = { + "none", + "initiator", + "responder", + "both" +}; + +JingleFactory::JingleFactory(Client *client) + : m_client(ClientPrivate::get(client)), m_state(AtRoot), m_depth(0), m_factory(0) +{ +} + +bool JingleFactory::checkSupport(const QSet<QString> &features) +{ + return features.contains(NS_JINGLE) && features.contains(NS_JINGLE_RTP); +} + +QStringList JingleFactory::features() const +{ + return QStringList(NS_JINGLE) << NS_JINGLE_RTP; +} + +bool JingleFactory::canParse(const QStringRef &name, const QStringRef &uri, + const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(attributes); + return name == QLatin1String("jingle") && uri == NS_JINGLE; +} + +void JingleFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, + const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(uri); + ++m_depth; + if (m_depth == 1) { + m_state = AtRoot; + m_jingle = Jingle::Ptr::create(); + m_jingle->initiator = attributes.value(QLatin1String("initiator")).toString(); + m_jingle->sid = attributes.value(QLatin1String("sid")).toString(); + m_jingle->action = strToEnum<Jingle::Action>(attributes.value(QLatin1String("action")), actions); + } else if (m_depth == 2 && m_state == AtRoot && name == QLatin1String("content")) { + m_state = AtContent; + m_content.reset(new Jingle::Content); + m_content->name = attributes.value(QLatin1String("name")).toString(); + m_content->senders = strToEnum<Jingle::SendersType>(attributes.value(QLatin1String("senders")), senders); + m_content->creator = strToEnum<Jingle::CreatorType>(attributes.value(QLatin1String("creator")), senders); + if (m_content->senders == Jingle::Invalid) + m_content->senders = Jingle::Both; + } else if (m_depth == 3 && m_state == AtContent) { + foreach (m_factory, m_client->factoriesByUri.values(uri.toString())) { + qDebug() << uri << Payload::payloadName(m_factory->payloadType()) + << m_factory->canParse(name, uri, attributes); + if (m_factory->canParse(name, uri, attributes)) + break; + else + m_factory = 0; + } + if (m_factory && name == QLatin1String("transport")) + m_state = AtTransport; + else if (m_factory && name == QLatin1String("description")) + m_state = AtDescription; + else + m_factory = 0; + qDebug() << name << uri << m_factory; + } + if (m_factory) + m_factory->handleStartElement(name, uri, attributes); +} + +void JingleFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + if (m_factory) { + m_factory->handleEndElement(name, uri); + if (m_depth == 3) { + if (m_state == AtTransport) + m_content->transports << m_factory->createPayload(); + else if (m_state == AtDescription) + m_content->description = m_factory->createPayload(); + else + Q_ASSERT(!"Unknown state with existen factory"); + m_factory = 0; + m_state = AtContent; + } + } else if (m_depth == 2 && m_state == AtContent) { + m_jingle->contents << *m_content; + m_content.reset(); + m_state = AtRoot; + } + + --m_depth; +} + +void JingleFactory::handleCharacterData(const QStringRef &text) +{ + if (m_factory) + m_factory->handleCharacterData(text); +} + +void JingleFactory::serialize(Payload *obj, QXmlStreamWriter *writer) +{ + Jingle *jingle = se_cast<Jingle*>(obj); + if (!jingle) return; + writer->writeStartElement(QLatin1String("jingle")); + writer->writeDefaultNamespace(NS_JINGLE); + writer->writeAttribute(QLatin1String("action"), enumToStr(jingle->action, actions)); + if (jingle->initiator.isValid()) + writer->writeAttribute(QLatin1String("initiator"), jingle->initiator); + if (jingle->responder.isValid()) + writer->writeAttribute(QLatin1String("responder"), jingle->responder); + writer->writeAttribute(QLatin1String("sid"), jingle->sid); + for (int i = 0; i < jingle->contents.size(); ++i) { + const Jingle::Content &content = jingle->contents.at(i); + writer->writeStartElement(QLatin1String("content")); + writer->writeAttribute(QLatin1String("creator"), enumToStr(content.creator, senders)); + writer->writeAttribute(QLatin1String("senders"), enumToStr(content.senders, senders)); + writer->writeAttribute(QLatin1String("name"), content.name); + AbstractPayloadFactory *factory = 0; + if (content.description) { + factory = m_client->factories.value(content.description->payloadType()); + if (factory) + factory->serialize(content.description.data(), writer); + } else { + qDebug("No description"); + } + for (int j = 0; j < content.transports.size(); ++j) { + Payload *payload = content.transports.at(j).data(); + factory = m_client->factories.value(payload->payloadType()); + if (factory) + factory->serialize(payload, writer); + } + writer->writeEndElement(); + } + writer->writeEndElement(); +} + +Payload::Ptr JingleFactory::createPayload() +{ + Payload::Ptr result = m_jingle; + m_jingle.clear(); + return result; +} + +}
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglefactory_p.h
Added
@@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLEFACTORY_P_H +#define JINGLEFACTORY_P_H + +#include "jingle_p.h" +#include "../client_p.h" + +namespace Jreen +{ + +class JingleFactory : public PayloadFactory<Jingle> +{ +public: + JingleFactory(Client *client); + + static bool checkSupport(const QSet<QString> &features); + virtual QStringList features() const; + virtual bool canParse(const QStringRef &name, const QStringRef &uri, + const QXmlStreamAttributes &attributes); + virtual void handleStartElement(const QStringRef &name, const QStringRef &uri, + const QXmlStreamAttributes &attributes); + virtual void handleEndElement(const QStringRef &name, const QStringRef &uri); + virtual void handleCharacterData(const QStringRef &text); + virtual void serialize(Payload *obj, QXmlStreamWriter *writer); + virtual Payload::Ptr createPayload(); + +private: + ClientPrivate *m_client; + enum State { AtRoot, AtContent, AtTransport, AtDescription, AtReason } m_state; + int m_depth; + Jingle::Ptr m_jingle; + AbstractPayloadFactory *m_factory; + QScopedPointer<Jingle::Content> m_content; +}; + +} + +#endif // JINGLEFACTORY_P_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglemanager.cpp
Added
@@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "jinglemanager_p.h" +#include "../client.h" +#include "jinglesession_p.h" +#include "jingletransportice_p.h" +#include "jingleaudiocontentfactory_p.h" + +namespace Jreen +{ + +JingleContent *JingleManagerPrivate::content(const QString &name, JingleSession *session) +{ + for (int i = 0; i < descriptions.size(); ++i) { + if (descriptions.at(i)->media() == name) + return descriptions.at(i)->createObject(session); + } + return 0; +} + +JingleContent *JingleManagerPrivate::content(const JingleDescription::Ptr &description, JingleSession *session) +{ + for (int i = 0; i < descriptions.size(); ++i) { + if (descriptions.at(i)->payloadType() == description->payloadType()) + return descriptions.at(i)->createObject(session); + } + return 0; +} + +JingleTransport *JingleManagerPrivate::transport(const JingleTransportInfo::Ptr &info, JingleContent *content) +{ + for (int i = 0; i < transports.size(); ++i) { + if (transports.at(i)->payloadType() == info->payloadType()) + return transports.at(i)->createObject(content); + } + return 0; +} + +void JingleManagerPrivate::_q_iqReceived(const Jreen::IQ &iq) +{ + Jingle::Ptr jingle = iq.payload<Jingle>(); + if (!jingle) + return; + qDebug() << Q_FUNC_INFO; + iq.accept(); + JingleSession *session = sessions.value(jingle->sid); + if (session) { + JingleSessionPrivate::get(session)->handle(jingle); + } else if (jingle->action == Jingle::SessionInitiate) { + new JingleSession(jingle, client); + } else { + IQ error(IQ::Error, iq.from(), iq.id()); + Jingle::Ptr result = Jingle::Ptr::create(); + result->sid = jingle->sid; + result->initiator = jingle->initiator; + result->action = Jingle::SessionTerminate; + // TODO: Add reason + client->send(error); + return; + } + IQ reply(IQ::Result, iq.from()); + client->send(reply); +} + +JingleManager::JingleManager(Client *client) + : QObject(client), d_ptr(new JingleManagerPrivate) +{ + Q_D(JingleManager); + d->client = client; +#ifdef HAVE_IRISICE + d->transports << new JingleIce::TransportFactory; +#endif + d->descriptions << new JingleAudioContentFactory; + client->registerPayload(new JingleFactory(client)); + foreach (AbstractPayloadFactory *factory, d->transports) + client->registerPayload(factory); + foreach (AbstractPayloadFactory *factory, d->descriptions) + client->registerPayload(factory); + connect(d->client, SIGNAL(iqReceived(Jreen::IQ)), + SLOT(_q_iqReceived(Jreen::IQ))); +} + +JingleManager::~JingleManager() +{ +} + +static inline bool set_contains_list(const QSet<QString> &features, const QStringList &list) +{ + bool ok = true; + for (int i = 0; ok && i < list.size(); ++i) + ok &= features.contains(list.at(i)); + return ok; +} + +bool JingleManager::checkSupport(const QSet<QString> &features) +{ + Q_D(JingleManager); + bool ok = JingleFactory::checkSupport(features); + if (!ok) return false; + ok = false; + for (int i = 0; !ok && i < d->transports.size(); ++i) + ok |= set_contains_list(features, d->transports.at(i)->features()); + if (!ok) return false; + ok = false; + for (int i = 0; !ok && i < d->descriptions.size(); ++i) + ok |= set_contains_list(features, d->descriptions.at(i)->features()); + return ok; +} + +bool JingleManager::hasSession(const JID &responder) +{ + return d_func()->sessionsByJid.contains(responder); +} + +JingleSession *JingleManager::createSession(const JID &responder, const QStringList &contents) +{ + Q_D(JingleManager); + if (JingleSession *session = d->sessionsByJid.value(responder)) + return session; + JingleSession *session = new JingleSession(responder, contents, d->client); + emit sessionCreated(session); + return session; +} + +JingleSession *JingleManager::session(const JID &jid) const +{ + return d_func()->sessionsByJid.value(jid); +} + +} + +#include "moc_jinglemanager.cpp"
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglemanager.h
Added
@@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLEMANAGER_H +#define JINGLEMANAGER_H + +#include "../iq.h" + +namespace Jreen +{ + +class Client; +class JingleSession; +class JingleManagerPrivate; + +class JREEN_EXPORT JingleManager : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(JingleManager) +public: + ~JingleManager(); + + bool checkSupport(const QSet<QString> &features); + bool hasSession(const JID &responder); + JingleSession *createSession(const JID &responder, const QStringList &contents = QStringList()); + JingleSession *session(const JID &jid) const; + +signals: + void sessionCreated(Jreen::JingleSession *session); + void sessionTerminated(Jreen::JingleSession *session); + +protected: + JingleManager(Client *client); + friend class Client; + QScopedPointer<JingleManagerPrivate> d_ptr; + Q_PRIVATE_SLOT(d_func(), void _q_iqReceived(const Jreen::IQ &)) +}; + +} + +#endif // JINGLEMANAGER_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglemanager_p.h
Added
@@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLEMANAGER_P_H +#define JINGLEMANAGER_P_H + +#include "jinglemanager.h" +#include "jinglefactory_p.h" + +namespace Jreen +{ + +class JingleManagerPrivate +{ +public: + Client *client; + QList<AbstractJingleTransportFactory*> transports; + QList<AbstractJingleContentFactory*> descriptions; + QHash<QString, JingleSession*> sessions; + QHash<JID, JingleSession*> sessionsByJid; + + JingleContent *content(const QString &name, JingleSession *session); + JingleContent *content(const JingleDescription::Ptr &decription, JingleSession *session); + JingleTransport *transport(const JingleTransportInfo::Ptr &info, JingleContent *content); + void _q_iqReceived(const Jreen::IQ &iq); + static JingleManagerPrivate *get(JingleManager *q) { return q->d_func(); } +}; + +} + +#endif // JINGLEMANAGER_P_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglesession.cpp
Added
@@ -0,0 +1,281 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "jinglesession_p.h" +#include "../client.h" +#include "../util.h" + +namespace Jreen +{ + +JingleSessionContent *JingleSessionPrivate::findContent(const QString &name) +{ + for (int i = 0; i < contents.size(); ++i) { + if (contents.at(i).name == name) + return &contentsi; + } + return 0; +} + +JingleSessionContent *JingleSessionPrivate::findContent(JingleContent *content) +{ + for (int i = 0; i < contents.size(); ++i) { + if (contentsi.contentObject == content) + return &contentsi; + } + return 0; +} + +void JingleSessionPrivate::handle(const Jingle::Ptr &jingle) +{ + qDebug() << Q_FUNC_INFO; + if (jingle->action == Jingle::SessionAccept) { + foreach (const Jingle::Content &remoteContent, jingle->contents) { + JingleSessionContent *content = findContent(remoteContent.name); + if (!content) { + qWarning("Unknown content with name %s", qPrintable(content->name)); + continue; + } + if (!remoteContent.description) { + qWarning("Unknown content description with name %s", qPrintable(content->name)); + continue; + } + content->contentObject->handleDescription(remoteContent.description); + if (remoteContent.transports.size() != 1) { + qWarning("Content %s has %d transports", qPrintable(content->name), + remoteContent.transports.size()); + } + if (!remoteContent.transports.value(0)) { + qCritical("Content %s has no transports", qPrintable(content->name)); + continue; + } + JingleContentPrivate *p = JingleContentPrivate::get(content->contentObject); + const JingleTransportInfo::Ptr &transportInfo = remoteContent.transports.at(0); + for (int i = content->transports.size() - 1; i >= 0; --i) { + if (content->transportsi->payloadType() != transportInfo->payloadType()) { + content->transports.removeAt(i); + delete p->transports.takeAt(i); + } + } + if (p->transports.isEmpty()) { + qCritical("Content %s has no needed transport", qPrintable(content->name)); + continue; + } + p->setTransport(p->transports.first()); + p->transport->setRemoteInfo(transportInfo, true); + } + } else if (jingle->action == Jingle::SessionTerminate) { + emit q_func()->terminated(); + } else if (jingle->action == Jingle::ContentAdd) { + foreach (const Jingle::Content &remoteContent, jingle->contents) { + if (!remoteContent.description || remoteContent.transports.isEmpty()) { + Jingle::send(q_func(), Jingle::ContentReject, remoteContent); + continue; + } + JingleSessionContent content = remoteContent; + content.creator = Jingle::Initiator; + JingleManagerPrivate *manager = JingleManagerPrivate::get(client->jingleManager()); + content.contentObject = manager->content(remoteContent.description, q_func()); + if (!content.contentObject) { + Jingle::send(q_func(), Jingle::ContentReject, remoteContent); + continue; + } + content.description = content.contentObject->handleDescription(remoteContent.description); + if (!content.description) { + content.description = content.contentObject->defaultDescription(); + Jingle::send(q_func(), Jingle::ContentReject, content); + continue; + } + JingleContentPrivate *contentD = JingleContentPrivate::get(content.contentObject); + contentD->needAccept = 1; + contents << content; + JingleContentPrivate::get(content.contentObject)->initiateTransports(content.transports); + emit q_func()->contentAdded(content.contentObject); + } + } +} + +void JingleSessionPrivate::accept(const JingleSessionContent &content) +{ + IQReply *reply = Jingle::send(q_func(), Jingle::ContentAccept, content); + Q_UNUSED(reply); +} + +void JingleSessionPrivate::add(const JingleSessionContent &content) +{ + IQReply *reply = Jingle::send(q_func(), Jingle::ContentAdd, content); + Q_UNUSED(reply); +} + +void JingleSessionPrivate::onTransportsReady(JingleContent *content, const QList<JingleTransport*> &transports) +{ + for (int i = 0; i < contents.size(); ++i) { + if (contents.at(i).contentObject != content) + continue; + JingleSessionContent &sessionContent = contentsi; + for (int j = 0; j < transports.size(); ++j) + sessionContent.transports << transportsj->localInfo(); + if (initiating) { + needMore--; + if (needMore == 0) + q_func()->initiate(); + } else { + JingleContentPrivate *p = JingleContentPrivate::get(content); + if (p->canAccept) + accept(sessionContent); + else + add(sessionContent); + } + } +} + +JingleSession::JingleSession(const JID &responder, const QStringList &contents, Client *client) + : QObject(client->jingleManager()), d_ptr(new JingleSessionPrivate) +{ + Q_D(JingleSession); + d->q_ptr = this; + d->incoming = 0; + d->client = client; + d->other = responder; + d->sid = Util::randomStringHash(16); + JingleManagerPrivate *manager = JingleManagerPrivate::get(client->jingleManager()); + manager->sessions.insert(d->sid, this); + manager->sessionsByJid.insert(responder, this); + for (int i = 0; i < contents.size(); ++i) + addContent(contents.at(i)); + if (d->needMore == 0 && d->contents.size() > 0) + initiate(); +} + +JingleSession::JingleSession(const Payload::Ptr &payload, Client *client) + : QObject(client->jingleManager()), d_ptr(new JingleSessionPrivate) +{ + Q_D(JingleSession); + Q_ASSERT(se_cast<Jingle*>(payload.data())); + d->client = client; + d->initiating = 0; + Jingle::Ptr jingle = payload.staticCast<Jingle>(); + d->other = jingle->initiator; + d->sid = jingle->sid; + JingleManagerPrivate *manager = JingleManagerPrivate::get(client->jingleManager()); + manager->sessions.insert(d->sid, this); + manager->sessionsByJid.insert(jingle->initiator, this); +} + +void JingleSession::initiate() +{ + Q_D(JingleSession); + IQReply *reply = Jingle::send(this, Jingle::SessionInitiate, d->contents); + Q_UNUSED(reply); +} + +void JingleSession::terminate() +{ + IQReply *reply = Jingle::send(this, Jingle::SessionTerminate); + connect(reply, SIGNAL(received(Jreen::IQ)), SIGNAL(terminated())); +} + +bool JingleSession::isIncoming() const +{ + return d_func()->incoming; +} + +JID JingleSession::jid() const +{ + return d_func()->other; +} + +JingleContent *JingleSession::content(const QString &id) const +{ + Q_D(const JingleSession); + for (int i = 0; i < d->contents.size(); ++i) { + if (d->contents.at(i).name == id) + return d->contents.at(i).contentObject; + } + return 0; +} + +QStringList JingleSession::contents() const +{ + Q_D(const JingleSession); + QStringList result; + for (int i = 0; i < d->contents.size(); ++i) + result << d->contents.at(i).name; + return result; +} + +JingleSession::~JingleSession() +{ + Q_D(JingleSession); + JingleManagerPrivate *manager = JingleManagerPrivate::get(d->client->jingleManager()); + manager->sessions.remove(d->sid); + manager->sessionsByJid.remove(d->other); +} + +bool JingleSession::addContent(const QString &media, const QString &id) +{ + Q_D(JingleSession); + JingleManagerPrivate *manager = JingleManagerPrivate::get(d->client->jingleManager()); + JingleSessionContent content; + content.creator = Jingle::Initiator; + content.contentObject = manager->content(media, this); + if (!content.contentObject) { + qWarning("Unknown content %s", qPrintable(media)); + return false; + } + content.description = content.contentObject->defaultDescription(); + content.name = id.isEmpty() ? Util::randomStringHash(8) : id; + JingleContentPrivate *contentD = JingleContentPrivate::get(content.contentObject); + contentD->initiateTransports(); + d->contents << content; + if (d->initiating) + d->needMore++; + emit contentAdded(content.contentObject); + return true; +} + +void JingleSession::accept() +{ + Q_D(JingleSession); + for (int i = 0; i < d->contents.size(); ++i) { + JingleContentPrivate *content = JingleContentPrivate::get(d->contents.at(i).contentObject); + if (content->needAccept) + content->accept(); + } +} + +void JingleSession::decline() +{ + Q_D(JingleSession); + for (int i = 0; i < d->contents.size(); ++i) { + JingleContentPrivate *content = JingleContentPrivate::get(d->contents.at(i).contentObject); + if (content->needAccept) + content->decline(); + } +} + +} + +#include "moc_jinglesession.cpp"
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglesession.h
Added
@@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLESESSION_H +#define JINGLESESSION_H + +#include "jinglecontent.h" +#include "../stanzaextension.h" + +namespace Jreen +{ + +class JingleManager; +class JingleManagerPrivate; +class JingleSessionPrivate; +class Client; +class JID; + +class JREEN_EXPORT JingleSession : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(JingleSession) +public: +// enum State { }; + + ~JingleSession(); + + bool addContent(const QString &content, const QString &id = QString()); + void initiate(); + void terminate(); + void accept(); + void decline(); + bool isIncoming() const; + JID jid() const; + JingleContent *content(const QString &id) const; + QStringList contents() const; + +signals: + void contentAdded(Jreen::JingleContent *content); + void contentRemoved(Jreen::JingleContent *content); + void terminated(); + +protected: + JingleSession(const JID &responder, const QStringList &contents, Client *client); + JingleSession(const Payload::Ptr &payload, Client *client); + friend class JingleManager; + friend class JingleManagerPrivate; + QScopedPointer<JingleSessionPrivate> d_ptr; +}; + +} + +#endif // JINGLESESSION_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglesession_p.h
Added
@@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLESESSION_P_H +#define JINGLESESSION_P_H + +#include "jinglesession.h" +#include "jinglemanager_p.h" +#include "jingle_p.h" +#include "jinglecontent_p.h" + +namespace Jreen +{ + +class JingleSessionContent : public Jingle::Content +{ +public: + JingleSessionContent() : contentObject(0), initiating(0) {} + JingleSessionContent(const Content &o) : Content(o), contentObject(0), initiating(0) {} + JingleSessionContent(const JingleSessionContent &o) + : Content(o), contentObject(o.contentObject), initiating(o.initiating) {} + + JingleContent *contentObject; + int initiating : 1; +}; + +class JingleSessionPrivate +{ +public: + Q_DECLARE_PUBLIC(JingleSession); + JingleSessionPrivate() : needMore(0), incoming(1), initiating(1) {} + JingleSession *q_ptr; + Client *client; + JID other; + QString sid; + QList<JingleSessionContent> contents; + int needMore : 30; + int incoming : 1; + int initiating : 1; + + JingleSessionContent *findContent(const QString &name); + JingleSessionContent *findContent(JingleContent *content); + void handle(const Jingle::Ptr &jingle); + void accept(const JingleSessionContent &content); + void add(const JingleSessionContent &content); + void onTransportsReady(JingleContent *content, const QList<JingleTransport*> &transports); + static JingleSessionPrivate *get(JingleSession *q) { return q->d_func(); } +}; + +} + +#endif // JINGLESESSION_P_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglespeexcodec.cpp
Added
@@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "jinglespeexcodec_p.h" + +#ifdef JREEN_HAVE_SPEEX + +namespace Jreen +{ + +JingleSpeexCodec::JingleSpeexCodec(const JingleAudioPayload &payload) +{ + const SpeexMode *mode = 0; + switch (payload.clockRate()) { + case 32000: + mode = &speex_uwb_mode; + break; + case 16000: + mode = &speex_wb_mode; + break; + default: + Q_ASSERT(!"Unknown clockrate"); + // fall through + // break; + case 8000: + mode = &speex_nb_mode; + break; + } + + speex_bits_init(&m_bits); + m_encodingState = speex_encoder_init(mode); + speex_encoder_ctl(m_encodingState, SPEEX_GET_FRAME_SIZE, &m_frameSize); + m_decodingState = speex_decoder_init(mode); + speex_decoder_ctl(m_decodingState, SPEEX_GET_FRAME_SIZE, &m_frameSize); + + QString quality = payload.parameter(QLatin1String("quality")); + if (!quality.isEmpty()) { + int value = quality.toInt(); + speex_encoder_ctl(m_encodingState, SPEEX_SET_QUALITY, &value); + } +} + +JingleSpeexCodec::~JingleSpeexCodec() +{ + speex_bits_destroy(&m_bits); + speex_encoder_destroy(m_encodingState); + speex_decoder_destroy(m_decodingState); +} + +int JingleSpeexCodec::frameSize() const +{ + return m_frameSize; +} + +QByteArray JingleSpeexCodec::encodeFrame(const char *data, int size) +{ + Q_ASSERT(size == m_frameSize * 2); + spx_int16_t *inputFrame = reinterpret_cast<spx_int16_t*>(const_cast<char*>(data)); + speex_bits_reset(&m_bits); + speex_encode_int(m_encodingState, inputFrame, &m_bits); + QByteArray frame(speex_bits_nbytes(&m_bits), Qt::Uninitialized); + int frameSize = speex_bits_write(&m_bits, frame.data(), frame.size()); + Q_ASSERT(frameSize == frame.size()); + return frame; +} + +QByteArray JingleSpeexCodec::decodeFrame(const char *data, int size) +{ + speex_bits_read_from(&m_bits, const_cast<char *>(data), size); + QByteArray output(m_frameSize * 2, Qt::Uninitialized); + spx_int16_t *outputFrame = reinterpret_cast<spx_int16_t*>(output.data()); + speex_decode_int(m_decodingState, &m_bits, outputFrame); + return output; +} + +QList<JingleAudioPayload> JingleSpeexCodecFactory::supportedPayloads() +{ + QList<JingleAudioPayload> result; + JingleAudioPayload payload; + payload.setId(97); + payload.setName(QLatin1String("speex")); + payload.setClockRate(8000); + result << payload; +// payload.setId(96); +// payload.setClockRate(16000); +// result << payload; +// payload.setId(98); +// payload.setClockRate(32000); +// result << payload; + return result; +} + +bool JingleSpeexCodecFactory::supportsPayload(const JingleAudioPayload &payload) +{ + return !payload.name().compare(QLatin1String("speex"), Qt::CaseInsensitive) + && payload.clockRate() == 8000; +} + +JingleAudioCodec *JingleSpeexCodecFactory::createCodec(const JingleAudioPayload &payload) +{ + return new JingleSpeexCodec(payload); +} + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/src/experimental/jinglespeexcodec_p.h
Added
@@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#if !defined(JINGLESPEEXCODEC_P_H) && defined(JREEN_HAVE_SPEEX) +#define JINGLESPEEXCODEC_P_H + +#include "jingleaudiocontent.h" +#include <speex/speex.h> + +namespace Jreen +{ + +class JingleSpeexCodec : public JingleAudioCodec +{ +public: + JingleSpeexCodec(const JingleAudioPayload &payload); + ~JingleSpeexCodec(); + + virtual int frameSize() const; + virtual QByteArray encodeFrame(const char *data, int size); + virtual QByteArray decodeFrame(const char *data, int size); + +private: + SpeexBits m_bits; + void *m_decodingState; + void *m_encodingState; + int m_frameSize; +}; + +class JingleSpeexCodecFactory : public JingleAudioCodecFactory +{ +public: + virtual QList<JingleAudioPayload> supportedPayloads(); + virtual bool supportsPayload(const JingleAudioPayload &payload); + virtual JingleAudioCodec *createCodec(const JingleAudioPayload &payload); +}; + +} + +#endif // JINGLESPEEXCODEC_P_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingletransport.cpp
Added
@@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "jingletransport.h" +#include "jinglesession.h" + +namespace Jreen +{ + +class JingleTransportPrivate +{ +public: + JingleTransportInfo::Ptr localInfo; + JingleTransport::State state; +}; + +JingleTransport::JingleTransport(JingleContent *content) + : QObject(content), d_ptr(new JingleTransportPrivate) +{ + Q_D(JingleTransport); + d->state = Gathering; +} + +JingleTransport::~JingleTransport() +{ +} + +JingleTransport::State JingleTransport::state() const +{ + return d_func()->state; +} + +JingleTransportInfo::Ptr JingleTransport::localInfo() const +{ + return d_func()->localInfo; +} + +void JingleTransport::setState(JingleTransport::State state) +{ + d_func()->state = state; + emit stateChanged(state); +} + +void JingleTransport::setLocalInfo(const JingleTransportInfo::Ptr &info) +{ + d_func()->localInfo = info; + emit localInfoReady(info); +} + +}
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingletransport.h
Added
@@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLETRANSPORT_H +#define JINGLETRANSPORT_H + +#include "jinglemanager.h" +#include "../stanzaextension.h" +#include <QSharedPointer> + +namespace Jreen +{ + +class JingleTransportPrivate; +class JingleContent; +typedef Payload JingleTransportInfo; + +class JingleTransport : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(JingleTransport) + Q_PROPERTY(Jreen::JingleTransport::State state READ state NOTIFY stateChanged) +public: + enum State { + Disconnected, + Gathering, + Connecting, + Connected, + Failed + }; + typedef QSharedPointer<JingleTransport> Ptr; + + JingleTransport(JingleContent *content); + virtual ~JingleTransport(); + + State state() const; + virtual void send(int component, const QByteArray &data) = 0; + JingleTransportInfo::Ptr localInfo() const; + virtual void setRemoteInfo(const JingleTransportInfo::Ptr &info, bool final) = 0; + +protected: + void setState(State state); + void setLocalInfo(const JingleTransportInfo::Ptr &info); + +signals: + void received(int component, const QByteArray &data); + void localInfoReady(const Jreen::JingleTransportInfo::Ptr &info); + void stateChanged(Jreen::JingleTransport::State); + +private: + QScopedPointer<JingleTransportPrivate> d_ptr; +}; + +class AbstractJingleTransportFactory : public AbstractPayloadFactory +{ +public: + inline JingleTransportInfo::Ptr createInfo() { return createPayload(); } + virtual JingleTransport *createObject(JingleContent *content) = 0; +}; + +template <typename Extension> +class JingleTransportFactory : public AbstractJingleTransportFactory +{ +public: + JingleTransportFactory(const QString &uri); + virtual ~JingleTransportFactory(); + + virtual int payloadType() const; + virtual QStringList features() const; + virtual bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + +protected: + const QString m_elementUri; +}; + +template <typename Extension> +Q_INLINE_TEMPLATE JingleTransportFactory<Extension>::JingleTransportFactory(const QString &uri) + : m_elementUri(uri) +{ +} + +template <typename Extension> +Q_INLINE_TEMPLATE JingleTransportFactory<Extension>::~JingleTransportFactory() +{ +} + +template <typename Extension> +Q_INLINE_TEMPLATE int JingleTransportFactory<Extension>::payloadType() const +{ + return Extension::staticPayloadType(); +} + +template <typename Extension> +Q_INLINE_TEMPLATE QStringList JingleTransportFactory<Extension>::features() const +{ + return QStringList(m_elementUri); +} + +template <typename Extension> +Q_INLINE_TEMPLATE bool JingleTransportFactory<Extension>::canParse(const QStringRef &name, const QStringRef &uri, + const QXmlStreamAttributes &) +{ + return name == QLatin1String("transport") && uri == m_elementUri; +} + +} + +#endif // JINGLETRANSPORT_H
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingletransportice.cpp
Added
@@ -0,0 +1,274 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "jingletransportice_p.h" + +#ifdef HAVE_IRISICE + +#include <QHostAddress> +#include <QNetworkInterface> +#include "jinglecontent.h" +#include "jinglesession.h" +#include "../jstrings.h" +#include "../util.h" + +#define NS_ICE_UDP QLatin1String("urn:xmpp:jingle:transports:ice-udp:1") + +namespace Jreen +{ +namespace JingleIce +{ + +static inline int addressPriority(const QHostAddress &address) +{ + if (address.protocol() == QAbstractSocket::IPv6Protocol) { + if (address == QHostAddress(QHostAddress::LocalHostIPv6)) + return 0; + if (XMPP::Ice176::isIPv6LinkLocalAddress(address)) + return 1; + } else if (address.protocol() == QAbstractSocket::IPv4Protocol) { + quint32 v4 = address.toIPv4Address(); + quint8 a0 = v4 >> 24; + quint8 a1 = (v4 >> 16) & 0xff; + if(a0 == 127) + return 0; + else if(a0 == 169 && a1 == 254) + return 1; + else if(a0 == 10) + return 2; + else if(a0 == 172 && a1 >= 16 && a1 <= 31) + return 2; + else if(a0 == 192 && a1 == 168) + return 2; + } + return 3; +} + +static inline bool addressLessThen(const QHostAddress &a, const QHostAddress &b) +{ + int cmp = addressPriority(a) - addressPriority(b); + if (cmp != 0) + return cmp < 0; + return a.protocol() == QAbstractSocket::IPv6Protocol + && b.protocol() != QAbstractSocket::IPv6Protocol; +} + +Transport::Transport(JingleContent *content) + : JingleTransport(content) +{ + QList<QHostAddress> addresses; + foreach (const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) { + if (networkInterface.flags() & QNetworkInterface::IsLoopBack) + continue; + foreach (const QNetworkAddressEntry &addressEntry, networkInterface.addressEntries()) { + QHostAddress address = addressEntry.ip(); + if(address.protocol() == QAbstractSocket::IPv6Protocol && XMPP::Ice176::isIPv6LinkLocalAddress(address)) + address.setScopeId(networkInterface.name()); + addresses << address; + } + } + qSort(addresses.begin(), addresses.end(), addressLessThen); + QList<XMPP::Ice176::LocalAddress> localAddresses; + foreach (const QHostAddress &address, addresses) { + XMPP::Ice176::LocalAddress localAddress; + localAddress.addr = address; + localAddresses << localAddress; + } + + m_ice = new XMPP::Ice176(this); + m_ice->setComponentCount(content->componentCount()); + for (int i = 0; i < content->componentCount(); ++i) + m_ready.insert(i); + m_ice->setLocalCandidateTrickle(true); + m_ice->setLocalAddresses(localAddresses); + m_portReserver = new XMPP::UdpPortReserver(m_ice); + m_portReserver->setAddresses(addresses); + m_portReserver->setPorts(qrand() & 0xffff, 4); + m_ice->setPortReserver(m_portReserver); + + connect(m_ice, SIGNAL(started()), SLOT(onIceStarted())); + connect(m_ice, SIGNAL(error(XMPP::Ice176::Error)), SLOT(onIceError(XMPP::Ice176::Error))); + connect(m_ice, SIGNAL(localCandidatesReady(const QList<XMPP::Ice176::Candidate> &)), SLOT(onIceLocalCandidatesReady(const QList<XMPP::Ice176::Candidate> &))); + connect(m_ice, SIGNAL(componentReady(int)), SLOT(onIceComponentReady(int)), Qt::QueuedConnection); // signal is not DOR-SS + connect(m_ice, SIGNAL(readyRead(int)), SLOT(onIceReadyRead(int))); + + m_ice->start(content->isAcceptable() ? XMPP::Ice176::Responder : XMPP::Ice176::Initiator); +} + +Transport::~Transport() +{ +} + +void Transport::send(int component, const QByteArray &data) +{ + m_ice->writeDatagram(component, data); +} + +void Transport::setRemoteInfo(const JingleTransportInfo::Ptr &genericInfo, bool final) +{ + Q_UNUSED(final); + qDebug() << Q_FUNC_INFO; + TransportInfo::Ptr info = genericInfo.staticCast<TransportInfo>(); + if (!info->ufrag.isEmpty()) + m_ice->setPeerUfrag(info->ufrag); + if (!info->pwd.isEmpty()) + m_ice->setPeerPassword(info->pwd); + m_ice->addRemoteCandidates(info->candidates); + setState(Connecting); +} + +void Transport::onIceStarted() +{ + qDebug() << Q_FUNC_INFO; +} + +void Transport::onIceError(XMPP::Ice176::Error error) +{ + qDebug() << Q_FUNC_INFO << error; + setState(Failed); +} + +void Transport::onIceLocalCandidatesReady(const QList<XMPP::Ice176::Candidate> &candidates) +{ + qDebug() << Q_FUNC_INFO; + TransportInfo::Ptr info = TransportInfo::Ptr::create(); + info->candidates = candidates; + info->ufrag = m_ice->localUfrag(); + info->pwd = m_ice->localPassword(); + setLocalInfo(info); +} + +void Transport::onIceComponentReady(int component) +{ + m_ready.remove(component); + qDebug() << Q_FUNC_INFO << component; + if (m_ready.isEmpty()) + setState(Connected); +} + +void Transport::onIceReadyRead(int component) +{ + while (m_ice->hasPendingDatagrams(component)) { + emit received(component, m_ice->readDatagram(component)); + } +} + +TransportFactory::TransportFactory() + : JingleTransportFactory<TransportInfo>(NS_ICE_UDP), m_depth(0) +{ +} + +JingleTransport *TransportFactory::createObject(JingleContent *content) +{ + return new Transport(content); +} + +void TransportFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attr) +{ + Q_UNUSED(uri); + m_depth++; + if (m_depth == 1) { + m_info = TransportInfo::Ptr::create(); + m_info->pwd = attr.value(QLatin1String("pwd")).toString(); + m_info->ufrag = attr.value(QLatin1String("ufrag")).toString(); + } else if (m_depth == 2 && name == QLatin1String("candidate")) { + m_info->candidates << Candidate(); + Candidate &cand = m_info->candidates.last(); + cand.type = attr.value(QLatin1String("type")).toString(); + cand.ip = QHostAddress(attr.value(QLatin1String("ip")).toString()); + cand.port = attr.value(QLatin1String("port")).toString().toInt(); + cand.network = attr.value(QLatin1String("network")).toString().toInt(); + cand.component = attr.value(QLatin1String("component")).toString().toInt(); + cand.priority = attr.value(QLatin1String("priority")).toString().toInt(); + cand.protocol = attr.value(QLatin1String("protocol")).toString(); + cand.foundation = attr.value(QLatin1String("foundation")).toString(); + cand.rel_addr = QHostAddress(attr.value(QLatin1String("rel-addr")).toString()); + cand.rel_port = attr.value(QLatin1String("rel-port")).toString().toInt(); + cand.generation = attr.value(QLatin1String("generation")).toString().toInt(); + cand.id = attr.value(QLatin1String("id")).toString(); + } +} + +void TransportFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + Q_UNUSED(name); + Q_UNUSED(uri); + m_depth--; +} + +void TransportFactory::handleCharacterData(const QStringRef &text) +{ + Q_UNUSED(text); +} + +void TransportFactory::serialize(Payload *obj, QXmlStreamWriter *writer) +{ + TransportInfo *info = se_cast<TransportInfo*>(obj); + Q_ASSERT(info); + writer->writeStartElement(QLatin1String("transport")); + writer->writeDefaultNamespace(m_elementUri); + if (!info->pwd.isEmpty()) + writer->writeAttribute(QLatin1String("pwd"), info->pwd); + if (!info->ufrag.isEmpty()) + writer->writeAttribute(QLatin1String("ufrag"), info->ufrag); + for (int i = 0; i < info->candidates.size(); ++i) { + const Candidate &c = info->candidates.at(i); + writer->writeEmptyElement(QLatin1String("candidate")); + writer->writeAttribute(QLatin1String("component"), QString::number(c.component)); + writer->writeAttribute(QLatin1String("foundation"), c.foundation); + writer->writeAttribute(QLatin1String("generation"), QString::number(c.generation)); + if(!c.id.isEmpty()) + writer->writeAttribute(QLatin1String("id"), c.id); + writer->writeAttribute(QLatin1String("ip"), c.ip.toString()); + if(c.network != -1) + writer->writeAttribute(QLatin1String("network"), QString::number(c.network)); + else // weird? + writer->writeAttribute(QLatin1String("network"), QString::number(0)); + writer->writeAttribute(QLatin1String("port"), QString::number(c.port)); + writer->writeAttribute(QLatin1String("priority"), QString::number(c.priority)); + writer->writeAttribute(QLatin1String("protocol"), c.protocol); + if(!c.rel_addr.isNull()) + writer->writeAttribute(QLatin1String("rel-addr"), c.rel_addr.toString()); + if(c.rel_port != -1) + writer->writeAttribute(QLatin1String("rel-port"), QString::number(c.rel_port)); + writer->writeAttribute("type", c.type); + } + writer->writeEndElement(); +} + +Payload::Ptr TransportFactory::createPayload() +{ + qDebug() << Q_FUNC_INFO << m_info->pwd << m_info->ufrag; + qDebug() << Q_FUNC_INFO << m_info->candidates.size(); + Payload::Ptr result = m_info; + m_info.clear(); + return result; +} + +} + +} + +#endif
View file
libjreen-1.1.0.tar.bz2/src/experimental/jingletransportice_p.h
Added
@@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JINGLEICE_H +#define JINGLEICE_H + +#include "jingletransport.h" + +#ifdef HAVE_IRISICE + +#include <QList> +#include "3rdparty/icesupport/ice176.h" +#include "3rdparty/icesupport/udpportreserver.h" +//#include <nice.h> + +namespace Jreen +{ +namespace JingleIce +{ + +class Transport : public JingleTransport +{ + Q_OBJECT +public: + Transport(JingleContent *content); + ~Transport(); + + virtual void send(int component, const QByteArray &data); + virtual void setRemoteInfo(const JingleTransportInfo::Ptr &info, bool final); + +private slots: + void onIceStarted(); + void onIceError(XMPP::Ice176::Error error); + void onIceLocalCandidatesReady(const QList<XMPP::Ice176::Candidate> &candidates); + void onIceComponentReady(int component); + void onIceReadyRead(int); + +private: + XMPP::Ice176 *m_ice; + XMPP::UdpPortReserver *m_portReserver; + QSet<int> m_ready; +}; + +typedef XMPP::Ice176::Candidate Candidate; + +class TransportInfo : public JingleTransportInfo +{ + J_PAYLOAD(Jreen::JingleIce::TransportInfo) +public: + QList<Candidate> candidates; + QString pwd; + QString ufrag; +}; + +class TransportFactory : public JingleTransportFactory<TransportInfo> +{ +public: + TransportFactory(); + + virtual JingleTransport *createObject(JingleContent *content); + virtual void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + virtual void handleEndElement(const QStringRef &name, const QStringRef &uri); + virtual void handleCharacterData(const QStringRef &text); + virtual void serialize(Payload *obj, QXmlStreamWriter *writer); + virtual Payload::Ptr createPayload(); + +private: + int m_depth; + TransportInfo::Ptr m_info; +}; + +} +} + +#endif // HAVE_IRISICE + +#endif // JINGLEICE_H
View file
libjreen-1.1.0.tar.bz2/src/forwarded.cpp
Added
@@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "forwarded.h" + +namespace Jreen +{ + +class ForwardedPrivate +{ +public: + ForwardedPrivate(const Message &m, const DelayedDelivery::Ptr &t) + : message(m), time(t) {} + Message message; + DelayedDelivery::Ptr time; +}; + +Forwarded::Forwarded(const Message &message, const DelayedDelivery::Ptr &time) + : d_ptr(new ForwardedPrivate(message, time)) +{ +} + +Forwarded::~Forwarded() +{ +} + +Message Forwarded::message() const +{ + return d_func()->message; +} + +void Forwarded::setMessage(const Message &message) +{ + d_func()->message = message; +} + +DelayedDelivery::Ptr Forwarded::time() const +{ + return d_func()->time; +} + +void Forwarded::setTime(const DelayedDelivery::Ptr &time) +{ + d_func()->time = time; +} +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/forwarded.h
Added
@@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_FORWARDED_H +#define JREEN_FORWARDED_H + +#include "message.h" + +namespace Jreen +{ + +class ForwardedPrivate; + +class JREEN_EXPORT Forwarded : public Payload +{ + J_PAYLOAD(Jreen::Forwarded) + Q_DECLARE_PRIVATE(Forwarded) +public: + Forwarded(const Message &message = Message(), const DelayedDelivery::Ptr &time = DelayedDelivery::Ptr()); + ~Forwarded(); + + Message message() const; + void setMessage(const Message &message); + + DelayedDelivery::Ptr time() const; + void setTime(const DelayedDelivery::Ptr &time); + +private: + QScopedPointer<ForwardedPrivate> d_ptr; +}; + +} // namespace Jreen + +#endif // JREEN_FORWARDED_H
View file
libjreen-1.1.0.tar.bz2/src/forwardedfactory.cpp
Added
@@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "forwardedfactory_p.h" + +#define NS_FORWARDED QLatin1String("urn:xmpp:forward:0") + +namespace Jreen +{ + +ForwardedFactory::ForwardedFactory(Client *client) + : m_messageFactory(client) +{ + m_depth = 0; + m_state = AtUnknown; +} + +QStringList ForwardedFactory::features() const +{ + return QStringList(NS_FORWARDED); +} + +bool ForwardedFactory::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(attributes); + return name == QLatin1String("forwarded") && uri == NS_FORWARDED; +} + +void ForwardedFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + ++m_depth; + if (m_depth == 1) { + m_forwarded.reset(new Forwarded); + } else if (m_depth == 2) { + if (m_delayedFactory.canParse(name, uri, attributes)) + m_state = AtDelayed; + else if (m_messageFactory.canParse(name, uri, attributes)) + m_state = AtMessage; + else + m_state = AtUnknown; + } + if (m_state == AtDelayed) + m_delayedFactory.handleStartElement(name, uri, attributes); + else if (m_state == AtMessage) + m_messageFactory.handleStartElement(name, uri, attributes); +} + +void ForwardedFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + if (m_state == AtDelayed) + m_delayedFactory.handleEndElement(name, uri); + else if (m_state == AtMessage) + m_messageFactory.handleEndElement(name, uri); + + if (m_depth == 2) { + if (m_state == AtDelayed) { + m_forwarded->setTime(m_delayedFactory.createPayload().staticCast<DelayedDelivery>()); + } else if (m_state == AtMessage) { + Stanza::Ptr message = m_messageFactory.createStanza(); + m_forwarded->setMessage(*message.staticCast<Message>().data()); + } + m_state = AtUnknown; + } + --m_depth; +} + +void ForwardedFactory::handleCharacterData(const QStringRef &text) +{ + if (m_state == AtDelayed) + m_delayedFactory.handleCharacterData(text); + else if (m_state == AtMessage) + m_messageFactory.handleCharacterData(text); +} + +void ForwardedFactory::serialize(Payload *extension, QXmlStreamWriter *writer) +{ + Forwarded *forwarded = payload_cast<Forwarded*>(extension); + writer->writeStartElement(QLatin1String("forwarded")); + writer->writeDefaultNamespace(NS_FORWARDED); + if (forwarded->time()) + m_delayedFactory.serialize(forwarded->time().data(), writer); + Message message = forwarded->message(); + m_messageFactory.serialize(&message, writer); + writer->writeEndElement(); +} + +Payload::Ptr ForwardedFactory::createPayload() +{ + return Payload::Ptr(m_forwarded.take()); +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/forwardedfactory_p.h
Added
@@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_FORWARDEDFACTORY_P_H +#define JREEN_FORWARDEDFACTORY_P_H + +#include "forwarded.h" +#include "messagefactory_p.h" +#include "delayeddeliveryfactory_p.h" + +namespace Jreen +{ + +class JREEN_AUTOTEST_EXPORT ForwardedFactory : public PayloadFactory<Forwarded> +{ +public: + ForwardedFactory(Client *client); + + QStringList features() const; + bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleEndElement(const QStringRef &name, const QStringRef &uri); + void handleCharacterData(const QStringRef &text); + void serialize(Payload *extension, QXmlStreamWriter *writer); + Payload::Ptr createPayload(); + +private: + enum State { + AtUnknown, + AtDelayed, + AtMessage + } m_state; + int m_depth; + MessageFactory m_messageFactory; + DelayedDeliveryFactory m_delayedFactory; + QScopedPointer<Forwarded> m_forwarded; +}; + +} // namespace Jreen + +#endif // JREEN_FORWARDEDFACTORY_P_H
View file
libjreen-1.0.3.tar.bz2/src/iq_p.h -> libjreen-1.1.0.tar.bz2/src/iq_p.h
Changed
@@ -34,7 +34,9 @@ class IQPrivate : public StanzaPrivate { public: - IQPrivate() : StanzaPrivate(StanzaIq), accepted(false), connection(false) {} + IQPrivate() + : StanzaPrivate(StanzaIq), subtype(IQ::Invalid), + accepted(false), connection(false) {} IQ::Type subtype; mutable bool accepted; bool connection;
View file
libjreen-1.0.3.tar.bz2/src/iqfactory.cpp -> libjreen-1.1.0.tar.bz2/src/iqfactory.cpp
Changed
@@ -31,7 +31,6 @@ { IqFactory::IqFactory(Client *client) : StanzaFactory(client) { - m_depth = 0; } int IqFactory::stanzaType() @@ -41,16 +40,15 @@ Stanza::Ptr IqFactory::createStanza() { - IQPrivate *p = new IQPrivate; - p->from = m_from; - p->to = m_to; - p->id = m_id; - p->subtype = m_type; - return Stanza::Ptr(new IQ(*p)); + return Stanza::Ptr(new IQ(*static_cast<IQPrivate*>(m_stanza.take()))); } void IqFactory::serialize(Stanza *stanza, QXmlStreamWriter *writer) { + if (!StanzaPrivate::get(*stanza)->tokens.isEmpty()) { + StanzaFactory::serialize(stanza, writer); + return; + } IQ *iq = static_cast<IQ*>(stanza); if (iq->subtype() == IQ::Invalid) return; @@ -87,35 +85,35 @@ void IqFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) { - Q_UNUSED(name); - Q_UNUSED(uri); m_depth++; + if (m_depth == 1) + m_stanza.reset(new IQPrivate); + StanzaFactory::handleStartElement(name, uri, attributes); if (m_depth == 1) { - parseAttributes(attributes); + IQPrivate *p = static_cast<IQPrivate*>(m_stanza.data()); QStringRef type = attributes.value(QLatin1String("type")); if (type == QLatin1String("get")) - m_type = IQ::Get; + p->subtype = IQ::Get; else if (type == QLatin1String("set")) - m_type = IQ::Set; + p->subtype = IQ::Set; else if (type == QLatin1String("result")) - m_type = IQ::Result; + p->subtype = IQ::Result; else if (type == QLatin1String("error")) - m_type = IQ::Error; + p->subtype = IQ::Error; else - m_type = IQ::Invalid; + p->subtype = IQ::Invalid; } } void IqFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) { + StanzaFactory::handleEndElement(name, uri); m_depth--; - Q_UNUSED(name); - Q_UNUSED(uri); } void IqFactory::handleCharacterData(const QStringRef &name) { - Q_UNUSED(name); + StanzaFactory::handleCharacterData(name); } }
View file
libjreen-1.0.3.tar.bz2/src/iqfactory_p.h -> libjreen-1.1.0.tar.bz2/src/iqfactory_p.h
Changed
@@ -31,7 +31,7 @@ namespace Jreen { -class IqFactory : public StanzaFactory +class JREEN_AUTOTEST_EXPORT IqFactory : public StanzaFactory { public: IqFactory(Client *client); @@ -42,9 +42,6 @@ void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); void handleEndElement(const QStringRef &name, const QStringRef &uri); void handleCharacterData(const QStringRef &name); -private: - int m_depth; - IQ::Type m_type; }; }
View file
libjreen-1.0.3.tar.bz2/src/jreen.h -> libjreen-1.1.0.tar.bz2/src/jreen.h
Changed
@@ -35,12 +35,22 @@ # include <QtCore/QXmlStreamWriter> //needed on OS X (10.5) for QXmlStreamWriter typedef # ifndef J_BUILD_STATIC +# ifdef J_BUILD_INTERNAL +# ifdef J_BUILD_LIBRARY +# define JREEN_AUTOTEST_EXPORT Q_DECL_EXPORT +# else +# define JREEN_AUTOTEST_EXPORT Q_DECL_IMPORT +# endif +# endif # ifdef J_BUILD_LIBRARY # define JREEN_EXPORT Q_DECL_EXPORT # else # define JREEN_EXPORT Q_DECL_IMPORT # endif # endif +# ifndef JREEN_AUTOTEST_EXPORT +# define JREEN_AUTOTEST_EXPORT +# endif # ifndef JREEN_EXPORT # define JREEN_EXPORT # endif
View file
libjreen-1.0.3.tar.bz2/src/jstrings.h -> libjreen-1.1.0.tar.bz2/src/jstrings.h
Changed
@@ -65,19 +65,19 @@ return -1; } -template<typename T, int N, typename X> -Q_INLINE_TEMPLATE int strToFlag(const T &str, const char *(&strings)N) +template<typename X, typename T, int N> +Q_INLINE_TEMPLATE X strToFlag(const T &str, const char *(&strings)N) { return static_cast<X>(strToFlag(str,strings)); } template<int N> -Q_INLINE_TEMPLATE QString flagToStr(int i, const char *(&strings)N) +Q_INLINE_TEMPLATE QString flagToStr(uint i, const char *(&strings)N) { - int n=1; - while(n < i) - n <<= 1; - if(n<0 || n>=N) + uint n = 1; + while ((1 << n) < i && n < N) + ++n; + if (n >= N) return QString(); return QLatin1String(stringsn); }
View file
libjreen-1.0.3.tar.bz2/src/logger.cpp -> libjreen-1.1.0.tar.bz2/src/logger.cpp
Changed
@@ -1,15 +1,15 @@ /**************************************************************************** ** -** qutIM - instant messenger +** Jreen ** ** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> ** ***************************************************************************** ** -** $QUTIM_BEGIN_LICENSE$ +** $JREEN_BEGIN_LICENSE$ ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or +** the Free Software Foundation, either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, @@ -19,7 +19,7 @@ ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see http://www.gnu.org/licenses/. -** $QUTIM_END_LICENSE$ +** $JREEN_END_LICENSE$ ** ****************************************************************************/
View file
libjreen-1.0.3.tar.bz2/src/logger.h -> libjreen-1.1.0.tar.bz2/src/logger.h
Changed
@@ -1,15 +1,15 @@ /**************************************************************************** ** -** qutIM - instant messenger +** Jreen ** ** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> ** ***************************************************************************** ** -** $QUTIM_BEGIN_LICENSE$ +** $JREEN_BEGIN_LICENSE$ ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or +** the Free Software Foundation, either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, @@ -19,7 +19,7 @@ ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see http://www.gnu.org/licenses/. -** $QUTIM_END_LICENSE$ +** $JREEN_END_LICENSE$ ** ****************************************************************************/
View file
libjreen-1.0.3.tar.bz2/src/message.cpp -> libjreen-1.1.0.tar.bz2/src/message.cpp
Changed
@@ -33,6 +33,13 @@ namespace Jreen { +Message::Message(Message::Type type) + : Stanza(*new MessagePrivate) +{ + Q_D(Message); + d->subtype = type; +} + Message::Message(Type type, const JID& to, const QString &body, const QString &subject, const QString &thread, const QString &xmllang) : Stanza(*new MessagePrivate) {
View file
libjreen-1.0.3.tar.bz2/src/message.h -> libjreen-1.1.0.tar.bz2/src/message.h
Changed
@@ -51,6 +51,7 @@ Normal, /**< A normal message. */ Invalid /**< The message stanza is invalid. */ }; + Message(Type type = Invalid); Message(Type type, const JID& to, const QString &body = QString(), const QString &subject = QString(), const QString &thread = QString(), const QString &xmllang = QString()); Message(MessagePrivate &p);
View file
libjreen-1.0.3.tar.bz2/src/message_p.h -> libjreen-1.1.0.tar.bz2/src/message_p.h
Changed
@@ -24,8 +24,10 @@ ****************************************************************************/ #ifndef MESSAGE_P_H #define MESSAGE_P_H + #include "stanza_p.h" #include "langmap.h" +#include "message.h" namespace Jreen { @@ -33,7 +35,7 @@ class MessagePrivate : public StanzaPrivate { public: - MessagePrivate() : StanzaPrivate(StanzaMessage) {} + MessagePrivate() : StanzaPrivate(StanzaMessage), subtype(Message::Normal) {} Message::Type subtype; LangMap body; LangMap subject;
View file
libjreen-1.0.3.tar.bz2/src/messagefactory.cpp -> libjreen-1.1.0.tar.bz2/src/messagefactory.cpp
Changed
@@ -31,26 +31,16 @@ namespace Jreen { static const char *message_types = { - "chat", - "error", - "groupchat", - "headline" + "chat", + "error", + "groupchat", + "headline", + "normal" }; MessageFactory::MessageFactory(Client *client) : - StanzaFactory(client), - m_depth(0) + StanzaFactory(client), m_state(AtMessage) { - clear(); -} - -void MessageFactory::clear() -{ - m_body.clear(); - m_subject.clear(); - m_thread.clear(); - m_subtype = Message::Normal; - m_state = AtMessage; } int MessageFactory::stanzaType() @@ -60,28 +50,25 @@ Stanza::Ptr MessageFactory::createStanza() { - MessagePrivate *p = new MessagePrivate; - p->from = m_from; - p->to = m_to; - p->id = m_id; - p->body = m_body; - p->subject = m_subject; - p->subtype = m_subtype; - p->thread = m_thread.toString(); - return Stanza::Ptr(new Message(*p)); + return Stanza::Ptr(new Message(*static_cast<MessagePrivate*>(m_stanza.take()))); } void MessageFactory::serialize(Stanza *stanza, QXmlStreamWriter *writer) { + if (!StanzaPrivate::get(*stanza)->tokens.isEmpty()) { + StanzaFactory::serialize(stanza, writer); + return; + } Message *message = static_cast<Message*>(stanza); if (message->subtype() == Message::Invalid) return; - QString subtype = enumToStr(message->subtype(),message_types); + QLatin1String subtype = enumToStr(message->subtype(),message_types); writer->writeStartElement(QLatin1String("message")); writeAttributes(stanza, writer); - writer->writeAttribute(QLatin1String("type"),subtype); + if (subtype != QLatin1String("")) + writer->writeAttribute(QLatin1String("type"), subtype); writeLangMap(QLatin1String("subject"),message->subject(),writer); writeLangMap(QLatin1String("body"),message->body(),writer); if(!message->thread().isEmpty()) @@ -100,13 +87,20 @@ void MessageFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) { - Q_UNUSED(uri); m_depth++; + if (m_depth == 1) + m_stanza.reset(new MessagePrivate); + StanzaFactory::handleStartElement(name, uri, attributes); if (m_depth == 1) { - clear(); - parseAttributes(attributes); + m_state = AtMessage; + MessagePrivate *p = static_cast<MessagePrivate*>(m_stanza.data()); QStringRef subtype = attributes.value(QLatin1String("type")); - m_subtype = strToEnum<Message::Type>(subtype,message_types); + if (subtype.isEmpty()) + p->subtype = Message::Normal; + else + p->subtype = strToEnum<Message::Type>(subtype, message_types); + if (p->subtype < 0) + p->subtype = Message::Invalid; } else if(m_depth == 2) { if(name == QLatin1String("body")) m_state = AtBody; @@ -119,8 +113,7 @@ void MessageFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) { - Q_UNUSED(name); - Q_UNUSED(uri); + StanzaFactory::handleEndElement(name, uri); if (m_depth == 2) m_state = AtMessage; m_depth--; @@ -128,13 +121,15 @@ void MessageFactory::handleCharacterData(const QStringRef &name) { + StanzaFactory::handleCharacterData(name); if(m_depth == 2) { + MessagePrivate *p = static_cast<MessagePrivate*>(m_stanza.data()); if(m_state == AtBody) - m_body = name.toString(); + p->body = name.toString(); else if(m_state == AtSubject) - m_subject = name.toString(); + p->subject = name.toString(); else if(m_state == AtThread) - m_thread = name; + p->thread = name.toString(); } }
View file
libjreen-1.0.3.tar.bz2/src/messagefactory_p.h -> libjreen-1.1.0.tar.bz2/src/messagefactory_p.h
Changed
@@ -31,7 +31,7 @@ namespace Jreen { -class MessageFactory : public StanzaFactory +class JREEN_AUTOTEST_EXPORT MessageFactory : public StanzaFactory { public: enum State { AtMessage, AtBody, AtSubject,AtThread }; @@ -44,13 +44,7 @@ void handleEndElement(const QStringRef &name, const QStringRef &uri); void handleCharacterData(const QStringRef &name); private: - void clear(); - int m_depth; - Message::Type m_subtype; - LangMap m_body; - LangMap m_subject; State m_state; - QStringRef m_thread; }; } // namespace Jreen
View file
libjreen-1.0.3.tar.bz2/src/messagesession.cpp -> libjreen-1.1.0.tar.bz2/src/messagesession.cpp
Changed
@@ -155,7 +155,7 @@ { Q_D(MessageSessionManager); d->client = client; - d->sessionHandlers.resize(Message::Invalid); + d->sessionHandlers.resize(Message::Invalid + 1); qsrand(QDateTime::currentDateTime().toTime_t()); connect(client, SIGNAL(messageReceived(Jreen::Message)), this, SLOT(handleMessage(Jreen::Message))); @@ -183,16 +183,19 @@ void MessageSessionManager::registerMessageSessionHandler(MessageSessionHandler *handler, QList<Message::Type> types) { - for(int i = 0; i < types.size(); i++) - d_func()->sessionHandlersi = handler; + for (int i = 0; i < types.size(); i++) { + Q_ASSERT(types.at(i) >= 0 && types.at(i) <= Message::Invalid); + d_func()->sessionHandlerstypes.at(i) = handler; + } } void MessageSessionManager::removeMessageSessionHandler(MessageSessionHandler *handler) { Q_D(MessageSessionManager); - for(int i = 0; i < d->sessionHandlers.size(); i++) + for (int i = 0; i < d->sessionHandlers.size(); i++) { if(d->sessionHandlersi == handler) d->sessionHandlersi = 0; + } } MessageSession *MessageSessionManager::session(const JID &jid, Message::Type type, bool create)
View file
libjreen-1.0.3.tar.bz2/src/messagesession.h -> libjreen-1.1.0.tar.bz2/src/messagesession.h
Changed
@@ -39,14 +39,24 @@ class MessageSessionManager; class Client; -#define J_MESSAGE_FILTER \ - public: \ - static const Jreen::MessageFilterMeta &meta() \ +#define J_MESSAGE_FILTER(Class) \ + public: \ + typedef QSharedPointer<Class> Ptr; \ + static int staticFilterType() \ { \ - static Jreen::MessageFilterMeta staticFilterMeta; \ - return staticFilterMeta; \ + static QBasicAtomicInt filterType = Q_BASIC_ATOMIC_INITIALIZER(0); \ + if (!filterType) { \ + filterType = Jreen::Payload::registerPayloadType( #Class ); \ + Class *useFullNameWithNamespaces = reinterpret_cast< ::Class* >(0); \ + Q_UNUSED(useFullNameWithNamespaces); \ + } \ + return filterType; \ + } \ + virtual int filterType() const \ + { \ + Q_UNUSED(static_cast<const ::Class*>(this)); \ + return staticFilterType(); \ } \ - virtual int filterType() const { return meta().type; } \ private: struct MessageFilterMeta
View file
libjreen-1.1.0.tar.bz2/src/metacontacts.cpp
Added
@@ -0,0 +1,30 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "metacontacts_p.h" + +namespace Jreen { + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/metacontacts_p.h
Added
@@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_METACONTACTS_P_H +#define JREEN_METACONTACTS_P_H + +#include "metacontactstorage.h" + +namespace Jreen +{ + +class JREEN_AUTOTEST_EXPORT MetaContacts : public Payload +{ + J_PAYLOAD(Jreen::MetaContacts) +public: + MetaContacts(MetaContactStorage::ItemList items) : items(items) {} + MetaContacts() {} + + MetaContactStorage::ItemList items; +}; + +} // namespace Jreen + +#endif // JREEN_METACONTACTS_P_H
View file
libjreen-1.1.0.tar.bz2/src/metacontactsfactory.cpp
Added
@@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "metacontactsfactory_p.h" +#include <QStringList> +#define NS_METACONTACTS QLatin1String("storage:metacontacts") + +namespace Jreen { + +MetaContactsFactory::MetaContactsFactory() +{ + m_depth = 0; +} + +MetaContactsFactory::~MetaContactsFactory() +{ +} + +QStringList MetaContactsFactory::features() const +{ + return QStringList(NS_METACONTACTS); +} + +bool MetaContactsFactory::canParse(const QStringRef &name, const QStringRef &uri, + const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(attributes); + return name == QLatin1String("storage") && uri == NS_METACONTACTS; +} + +void MetaContactsFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, + const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(uri); + m_depth++; + if(m_depth == 1) { + m_metacontacts.reset(new MetaContacts); + } else if (m_depth == 2 && name == QLatin1String("meta")) { + Jreen::MetaContactStorage::Item item; + item.setJID(attributes.value(QLatin1String("jid")).toString()); + item.setTag(attributes.value(QLatin1String("tag")).toString()); + QString orderStr = attributes.value(QLatin1String("order")).toString(); + bool ok = true; + uint order = orderStr.toUInt(&ok); + if (ok) + item.setOrder(order); + m_metacontacts->items << item; + } +} + +void MetaContactsFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + Q_UNUSED(name); + Q_UNUSED(uri); + m_depth--; +} + +void MetaContactsFactory::handleCharacterData(const QStringRef &text) +{ + Q_UNUSED(text); +} + +void MetaContactsFactory::serialize(Payload *extension, QXmlStreamWriter *writer) +{ + MetaContacts *metacontacts = se_cast<MetaContacts*>(extension); + writer->writeStartElement(QLatin1String("storage")); + writer->writeDefaultNamespace(NS_METACONTACTS); + foreach (const MetaContactStorage::Item &item, metacontacts->items) { + writer->writeStartElement(QLatin1String("meta")); + writer->writeAttribute(QLatin1String("jid"), item.jid().full()); + writer->writeAttribute(QLatin1String("tag"), item.tag()); + if (item.hasOrder()) + writer->writeAttribute(QLatin1String("order"), QString::number(item.order())); + writer->writeEndElement(); + } + writer->writeEndElement(); +} + +Payload::Ptr MetaContactsFactory::createPayload() +{ + return Payload::Ptr(m_metacontacts.take()); +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/metacontactsfactory_p.h
Added
@@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_METACONTACTSFACTORY_P_H +#define JREEN_METACONTACTSFACTORY_P_H + +#include "metacontacts_p.h" + +namespace Jreen { + +class JREEN_AUTOTEST_EXPORT MetaContactsFactory : public PayloadFactory<MetaContacts> +{ +public: + MetaContactsFactory(); + ~MetaContactsFactory(); + QStringList features() const; + bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleEndElement(const QStringRef &name, const QStringRef &uri); + void handleCharacterData(const QStringRef &text); + void serialize(Payload *extension, QXmlStreamWriter *writer); + Payload::Ptr createPayload(); +private: + int m_depth; + QScopedPointer<MetaContacts> m_metacontacts; +}; + +} // namespace Jreen + +#endif // JREEN_METACONTACTSFACTORY_P_H
View file
libjreen-1.1.0.tar.bz2/src/metacontactstorage.cpp
Added
@@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "metacontactstorage.h" +#include "metacontacts_p.h" +#include "logger.h" +#include "client.h" + +namespace Jreen { + +class MetaContactStorage::ItemData : public QSharedData +{ +public: + ItemData() : order(-1) {} + ItemData(const ItemData &o) + : QSharedData(o), jid(o.jid), tag(o.tag), order(o.order) {} + + JID jid; + QString tag; + qint64 order; +}; + +MetaContactStorage::Item::Item() : d(new ItemData) +{ +} + +MetaContactStorage::Item::Item(const JID &jid, const QString &tag) : d(new MetaContactStorage::ItemData) +{ + d->jid = jid; + d->tag = tag; +} + +MetaContactStorage::Item::Item(const JID &jid, const QString &tag, uint order) : d(new MetaContactStorage::ItemData) +{ + d->jid = jid; + d->tag = tag; + d->order = order; +} + +MetaContactStorage::Item::Item(const MetaContactStorage::Item &item) : d(item.d) +{ +} + +MetaContactStorage::Item &MetaContactStorage::Item::operator =(const MetaContactStorage::Item &item) +{ + d = item.d; + return *this; +} + +MetaContactStorage::Item::~Item() +{ +} + +JID MetaContactStorage::Item::jid() const +{ + return d->jid; +} + +void MetaContactStorage::Item::setJID(const JID &jid) +{ + d->jid = jid; +} + +QString MetaContactStorage::Item::tag() const +{ + return d->tag; +} + +void MetaContactStorage::Item::setTag(const QString &tag) +{ + d->tag = tag; +} + +uint MetaContactStorage::Item::order() const +{ + return uint(d->order); +} + +bool MetaContactStorage::Item::hasOrder() const +{ + return d->order >= 0; +} + +void MetaContactStorage::Item::clearOrder() +{ + d->order = -1; +} + +void MetaContactStorage::Item::setOrder(uint order) +{ + d->order = order; +} + +class MetaContactStoragePrivate +{ +public: + Client *client; + QWeakPointer<PrivateXml> privateXml; +}; + +MetaContactStorage::MetaContactStorage(Client *client) : + QObject(client), d_ptr(new MetaContactStoragePrivate) +{ + Q_D(MetaContactStorage); + d->client = client; +} + +MetaContactStorage::~MetaContactStorage() +{ +} + +void MetaContactStorage::setPrivateXml(PrivateXml *privateXml) +{ + d_func()->privateXml = privateXml; +} + +void MetaContactStorage::requestMetaContacts() +{ + Q_D(MetaContactStorage); + if (!d->privateXml) + return; + d->privateXml.data()->request(QLatin1String("storage"), QLatin1String("storage:metacontacts"), this, + SLOT(onResultReady(Jreen::Payload::Ptr,Jreen::PrivateXml::Result,Jreen::Error::Ptr))); +} + +void MetaContactStorage::storeMetaContacts(const MetaContactStorage::ItemList &items) +{ + Q_D(MetaContactStorage); + if (!d->privateXml) + return; + d->privateXml.data()->store(MetaContacts::Ptr(new MetaContacts(items)), this, + SLOT(onResultReady(Jreen::Payload::Ptr,Jreen::PrivateXml::Result,Jreen::Error::Ptr))); +} + +void MetaContactStorage::onResultReady(const Payload::Ptr &payload, PrivateXml::Result result, const Error::Ptr &error) +{ + Q_UNUSED(error); + Logger::debug() << "onResultReady"; + if(result == PrivateXml::RequestOk) { + MetaContacts *metacontacts = payload_cast<MetaContacts*>(payload.data()); + Logger::debug() << "received metacontacts" << metacontacts << payload.data(); + if (metacontacts) + emit metaContactsReceived(metacontacts->items); + else + emit metaContactsReceived(ItemList()); + } +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/metacontactstorage.h
Added
@@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_METACONTACTSTORAGE_H +#define JREEN_METACONTACTSTORAGE_H + +#include "jid.h" +#include "privatexml.h" +#include "error.h" + +namespace Jreen +{ + +class MetaContactStoragePrivate; + +class JREEN_EXPORT MetaContactStorage : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(MetaContactStorage) +public: + class ItemData; + class Item + { + public: + Item(); + Item(const JID &jid, const QString &tag); + Item(const JID &jid, const QString &tag, uint order); + Item(const Item &item); + Item &operator =(const Item &item); + ~Item(); + + JID jid() const; + void setJID(const JID &jid); + QString tag() const; + void setTag(const QString &tag); + uint order() const; + bool hasOrder() const; + void clearOrder(); + void setOrder(uint order); + + private: + QSharedDataPointer<ItemData> d; + }; + typedef QList<Item> ItemList; + + MetaContactStorage(Client *client); + ~MetaContactStorage(); + + void setPrivateXml(PrivateXml *privateXml); + + void requestMetaContacts(); + void storeMetaContacts(const ItemList &items); + +signals: + void metaContactsReceived(const Jreen::MetaContactStorage::ItemList &items); + +private slots: + void onResultReady(const Jreen::Payload::Ptr &,Jreen::PrivateXml::Result,const Jreen::Error::Ptr &); + +private: + QScopedPointer<MetaContactStoragePrivate> d_ptr; +}; + +} // namespace Jreen + +#endif // JREEN_METACONTACTSTORAGE_H
View file
libjreen-1.0.3.tar.bz2/src/moodfactory_p.h -> libjreen-1.1.0.tar.bz2/src/moodfactory_p.h
Changed
@@ -31,7 +31,7 @@ namespace Jreen { -class MoodFactory : public PayloadFactory<Mood> +class JREEN_AUTOTEST_EXPORT MoodFactory : public PayloadFactory<Mood> { public: MoodFactory();
View file
libjreen-1.0.3.tar.bz2/src/mucroom.cpp -> libjreen-1.1.0.tar.bz2/src/mucroom.cpp
Changed
@@ -199,6 +199,7 @@ Q_Q(MUCRoom); Logger::debug() << "handle presence" << pres.from(); if (Error::Ptr e = pres.payload<Error>()) { + startedJoining = false; emit q->error(e); return; } @@ -312,9 +313,9 @@ void MUCRoom::join(Presence::Type type, const QString &message, int priority) { Q_D(MUCRoom); - if (!isJoined()) { - d->startedJoining = true; - } + if (d->startedJoining) + return; + d->startedJoining = true; Presence pres(type, d->jid, message, priority); MUCRoomQuery *query = new MUCRoomQuery(d->password); query->setMaxChars(d->maxChars); @@ -587,6 +588,7 @@ void MUCRoom::onDisconnected() { Q_D(MUCRoom); + d->startedJoining = false; if (d->currentPresence.subtype() != Presence::Unavailable) { d->participantsHash.clear(); d->isJoined = false;
View file
libjreen-1.0.3.tar.bz2/src/mucroom_p.h -> libjreen-1.1.0.tar.bz2/src/mucroom_p.h
Changed
@@ -86,7 +86,7 @@ int m_maxStanzas; int m_seconds; QDateTime m_since; - friend class MUCRoomQueryFactory; + friend class JREEN_AUTOTEST_EXPORT MUCRoomQueryFactory; }; class MUCRoomItem
View file
libjreen-1.0.3.tar.bz2/src/mucroomfactory_p.h -> libjreen-1.1.0.tar.bz2/src/mucroomfactory_p.h
Changed
@@ -31,7 +31,7 @@ namespace Jreen { -class MUCRoomQueryFactory : public PayloadFactory<MUCRoomQuery> +class JREEN_AUTOTEST_EXPORT MUCRoomQueryFactory : public PayloadFactory<MUCRoomQuery> { public: MUCRoomQueryFactory(); @@ -45,7 +45,7 @@ Payload::Ptr createPayload(); }; -class MUCRoomItemFactory : public XmlStreamFactory<MUCRoomItem> +class JREEN_AUTOTEST_EXPORT MUCRoomItemFactory : public XmlStreamFactory<MUCRoomItem> { public: MUCRoomItemFactory(); @@ -62,7 +62,7 @@ QScopedPointer<MUCRoomItem> m_item; }; -class MUCRoomUserQueryFactory : public PayloadFactory<MUCRoomUserQuery> +class JREEN_AUTOTEST_EXPORT MUCRoomUserQueryFactory : public PayloadFactory<MUCRoomUserQuery> { public: MUCRoomUserQueryFactory(); @@ -82,7 +82,7 @@ State m_state; }; -class MUCRoomAdminQueryFactory : public PayloadFactory<MUCRoomAdminQuery> +class JREEN_AUTOTEST_EXPORT MUCRoomAdminQueryFactory : public PayloadFactory<MUCRoomAdminQuery> { public: MUCRoomAdminQueryFactory(); @@ -101,7 +101,7 @@ QScopedPointer<MUCRoomAdminQuery> m_query; }; -class MUCRoomOwnerQueryFactory : public PayloadFactory<MUCRoomOwnerQuery> +class JREEN_AUTOTEST_EXPORT MUCRoomOwnerQueryFactory : public PayloadFactory<MUCRoomOwnerQuery> { public: MUCRoomOwnerQueryFactory();
View file
libjreen-1.0.3.tar.bz2/src/nicknamefactory.cpp -> libjreen-1.1.0.tar.bz2/src/nicknamefactory.cpp
Changed
@@ -29,7 +29,7 @@ namespace Jreen { -class NicknameFactoryPrivate +class JREEN_AUTOTEST_EXPORT NicknameFactoryPrivate { public: QString nickname;
View file
libjreen-1.0.3.tar.bz2/src/nicknamefactory_p.h -> libjreen-1.1.0.tar.bz2/src/nicknamefactory_p.h
Changed
@@ -29,8 +29,8 @@ namespace Jreen { -class NicknameFactoryPrivate; -class NicknameFactory : public PayloadFactory<Nickname> +class JREEN_AUTOTEST_EXPORT NicknameFactoryPrivate; +class JREEN_AUTOTEST_EXPORT NicknameFactory : public PayloadFactory<Nickname> { Q_DECLARE_PRIVATE(NicknameFactory) public:
View file
libjreen-1.0.3.tar.bz2/src/nonsaslauth.cpp -> libjreen-1.1.0.tar.bz2/src/nonsaslauth.cpp
Changed
@@ -30,6 +30,8 @@ #include "client.h" #include "jstrings.h" +#define NS_IQ_AUTH QLatin1String("http://jabber.org/features/iq-auth") + namespace Jreen { @@ -37,7 +39,7 @@ { Q_UNUSED(uri); Q_UNUSED(attributes); - return name == QLatin1String("auth") && uri == QLatin1String("http://jabber.org/features/iq-auth"); + return name == QLatin1String("auth") && uri == NS_IQ_AUTH; } void NonSaslAuth::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes)
View file
libjreen-1.0.3.tar.bz2/src/parser.cpp -> libjreen-1.1.0.tar.bz2/src/parser.cpp
Changed
@@ -74,7 +74,45 @@ d->parsers.clear(); foreach (StreamFeature *feature, d->client->features) feature->reset(); - d->extensions.clear(); +} + +static Client::Feature convertToFeature(int type) +{ + switch (type) { + case StreamFeature::CompressionLayer: + return Client::Compression; + case StreamFeature::SecurityLayer: + return Client::Encryption; + case StreamFeature::SASL: + case StreamFeature::SimpleAuthorization: + return Client::Authorization; + default: + return Client::InvalidFeature; + } +} + +static Client::DisconnectReason convertToReason(Client::Feature feature) +{ + switch (feature) { + case Client::Encryption: + return Client::NoEncryptionSupport; + case Client::Compression: + return Client::NoCompressionSupport; + case Client::Authorization: + return Client::NoAuthorizationSupport; + default: + return Client::NoSupportedFeature; + } +} + +static bool checkFeature(ClientPrivate *client, Client::Feature feature) +{ + if (client->configsfeature == Client::Force + && !(client->usedFeatures & (1 << feature))) { + client->emitDisconnected(convertToReason(feature)); + return false; + } + return true; } void Parser::activateFeature() @@ -82,14 +120,34 @@ Q_D(Parser); int i = d->client->features.indexOf(d->client->current_stream_feature) + 1; d->client->current_stream_feature = 0; + bool foundAny = false; for (; i < d->client->features.size(); i++) { StreamFeature *feature = d->client->features.at(i); - if (feature->isActivatable()) { - d->client->current_stream_feature = feature; - feature->activate(); - break; + if (!feature->isActivatable()) + continue; + Client::Feature clientFeature = convertToFeature(feature->type()); + Client::FeatureConfig config = d->client->configs.value(clientFeature, Client::Auto); + if (config == Client::Disable) + continue; + if (clientFeature == Client::InvalidFeature + && (!checkFeature(d->client, Client::Encryption) + || !checkFeature(d->client, Client::Compression) + || !checkFeature(d->client, Client::Authorization))) { + return; + } + if (clientFeature == Client::Authorization + && !checkFeature(d->client, Client::Encryption)) { + return; } + d->client->current_stream_feature = feature; + foundAny = true; + feature->activate(); + if (clientFeature != Client::InvalidFeature) + d->client->usedFeatures |= (1 << clientFeature); + break; } + if (!foundAny) + d->client->emitDisconnected(Client::NoSupportedFeature); } #define XML_HEADER "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" @@ -187,11 +245,6 @@ if (feature->canParse(name, uri, attributes)) d->parsers.append(feature); } - } else if (d->state == ReadStanza && d->depth == 2) { - foreach (AbstractPayloadFactory *factory, d->client->factories) { - if (factory->canParse(name, uri, attributes)) - d->parsers.append(factory); - } } foreach (XmlStreamParser *parser, d->parsers) parser->handleStartElement(name, uri, attributes); @@ -213,11 +266,6 @@ for (int i = 0; i < d->parsers.size(); i++) { XmlStreamParser *parser = d->parsers.at(i); parser->handleEndElement(name, uri); - if (d->depth == 2 && d->state == ReadStanza && i > d->parsersCount.at(1)) { - Payload::Ptr se; - se = static_cast<AbstractPayloadFactory*>(parser)->createPayload(); - d->extensions.append(se); - } } #ifdef PARSER_DEBUG_SPEED d->parsingTime += counter.elapsed(); @@ -232,14 +280,11 @@ } else if (d->state == ReadStanza) { StanzaFactory *factory = static_cast<StanzaFactory*>(d->parsers.top()); Stanza::Ptr stanza = factory->createStanza(); - foreach (const Payload::Ptr &se, d->extensions) - stanza->addExtension(se); #ifdef PARSER_DEBUG_SPEED d->parsingTime += counter.elapsed(); counter.restart(); #endif d->client->handleStanza(stanza); - d->extensions.clear(); #ifdef PARSER_DEBUG_SPEED d->stanzaLogicTimefactory->stanzaType() += counter.elapsed(); #endif
View file
libjreen-1.0.3.tar.bz2/src/parser_p.h -> libjreen-1.1.0.tar.bz2/src/parser_p.h
Changed
@@ -56,7 +56,6 @@ Parser::State state; QStack<XmlStreamParser*> parsers; QStack<int> parsersCount; - QList<Payload::Ptr> extensions; QByteArray buffer; int depth; bool atParsing;
View file
libjreen-1.1.0.tar.bz2/src/pgpencrypted.cpp
Added
@@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "pgpencrypted.h" + +namespace Jreen +{ + +class PGPEncryptedPrivate +{ +public: + QString encryptedText; +}; + +PGPEncrypted::PGPEncrypted(const QString &encryptedText) : d_ptr(new PGPEncryptedPrivate) +{ + d_func()->encryptedText = encryptedText; +} + +PGPEncrypted::~PGPEncrypted() +{ +} + +QString PGPEncrypted::encryptedText() const +{ + return d_func()->encryptedText; +} + +void PGPEncrypted::setEncryptedText(const QString &encryptedText) +{ + d_func()->encryptedText = encryptedText; +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/pgpencrypted.h
Added
@@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_PGPENCRYPTED_H +#define JREEN_PGPENCRYPTED_H + +#include "stanzaextension.h" + +namespace Jreen +{ + +class PGPEncryptedPrivate; + +class JREEN_EXPORT PGPEncrypted : public Payload +{ + J_PAYLOAD(Jreen::PGPEncrypted) + Q_DECLARE_PRIVATE(PGPEncrypted) +public: + PGPEncrypted(const QString &encryptedText = QString()); + ~PGPEncrypted(); + + QString encryptedText() const; + void setEncryptedText(const QString &encryptedText); + +private: + QScopedPointer<PGPEncryptedPrivate> d_ptr; +}; +} // namespace Jreen + +#endif // JREEN_PGPENCRYPTED_H
View file
libjreen-1.1.0.tar.bz2/src/pgpfactory.cpp
Added
@@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "pgpfactory_p.h" +#include <QStringList> + +#define NS_SIGNED QLatin1String("jabber:x:signed") +#define NS_ENCRYPTED QLatin1String("jabber:x:encrypted") + +namespace Jreen +{ + +PGPSignedFactory::PGPSignedFactory() : m_depth(0) +{ +} + +QStringList PGPSignedFactory::features() const +{ + return QStringList(NS_SIGNED); +} + +bool PGPSignedFactory::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(attributes); + return name == QLatin1String("x") && uri == NS_SIGNED; +} + +void PGPSignedFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(name); + Q_UNUSED(uri); + Q_UNUSED(attributes); + m_depth++; + if (m_depth == 1) + m_query.reset(new PGPSigned); +} + +void PGPSignedFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + Q_UNUSED(name); + Q_UNUSED(uri); + --m_depth; +} + +void PGPSignedFactory::handleCharacterData(const QStringRef &text) +{ + Q_UNUSED(text); + if (m_depth == 1) + m_query->setSignature(text.toString()); +} + +void PGPSignedFactory::serialize(Payload *extension, QXmlStreamWriter *writer) +{ + PGPSigned *query = payload_cast<PGPSigned*>(extension); + writer->writeStartElement(QLatin1String("x")); + writer->writeDefaultNamespace(NS_SIGNED); + writer->writeCharacters(query->signature()); + writer->writeEndElement(); +} + +Payload::Ptr PGPSignedFactory::createPayload() +{ + return Payload::Ptr(m_query.take()); +} + +PGPEncryptedFactory::PGPEncryptedFactory() : m_depth(0) +{ +} + +QStringList PGPEncryptedFactory::features() const +{ + return QStringList(NS_ENCRYPTED); +} + +bool PGPEncryptedFactory::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(attributes); + return name == QLatin1String("x") && uri == NS_ENCRYPTED; +} + +void PGPEncryptedFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(name); + Q_UNUSED(uri); + Q_UNUSED(attributes); + m_depth++; + if (m_depth == 1) + m_query.reset(new PGPEncrypted); +} + +void PGPEncryptedFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + Q_UNUSED(name); + Q_UNUSED(uri); + --m_depth; +} + +void PGPEncryptedFactory::handleCharacterData(const QStringRef &text) +{ + Q_UNUSED(text); + if (m_depth == 1) + m_query->setEncryptedText(text.toString()); +} + +void PGPEncryptedFactory::serialize(Payload *extension, QXmlStreamWriter *writer) +{ + PGPEncrypted *query = payload_cast<PGPEncrypted*>(extension); + writer->writeStartElement(QLatin1String("x")); + writer->writeDefaultNamespace(NS_ENCRYPTED); + writer->writeCharacters(query->encryptedText()); + writer->writeEndElement(); +} + +Payload::Ptr PGPEncryptedFactory::createPayload() +{ + return Payload::Ptr(m_query.take()); +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/pgpfactory_p.h
Added
@@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_PGPFACTORY_H +#define JREEN_PGPFACTORY_H + +#include "pgpsigned.h" +#include "pgpencrypted.h" + +namespace Jreen { + +class JREEN_AUTOTEST_EXPORT PGPSignedFactory : public PayloadFactory<PGPSigned> +{ +public: + PGPSignedFactory(); + QStringList features() const; + bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleEndElement(const QStringRef &name, const QStringRef &uri); + void handleCharacterData(const QStringRef &text); + void serialize(Payload *extension, QXmlStreamWriter *writer); + Payload::Ptr createPayload(); +private: + int m_depth; + QScopedPointer<PGPSigned> m_query; +}; + +class JREEN_AUTOTEST_EXPORT PGPEncryptedFactory : public PayloadFactory<PGPEncrypted> +{ +public: + PGPEncryptedFactory(); + QStringList features() const; + bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleEndElement(const QStringRef &name, const QStringRef &uri); + void handleCharacterData(const QStringRef &text); + void serialize(Payload *extension, QXmlStreamWriter *writer); + Payload::Ptr createPayload(); +private: + int m_depth; + QScopedPointer<PGPEncrypted> m_query; +}; + +} // namespace Jreen + +#endif // JREEN_PGPFACTORY_H
View file
libjreen-1.1.0.tar.bz2/src/pgpsigned.cpp
Added
@@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "pgpsigned.h" + +namespace Jreen +{ + +class PGPSignedPrivate +{ +public: + QString signature; +}; + +PGPSigned::PGPSigned(const QString &signature) : d_ptr(new PGPSignedPrivate) +{ + d_func()->signature = signature; +} + +PGPSigned::~PGPSigned() +{ +} + +QString PGPSigned::signature() const +{ + return d_func()->signature; +} + +void PGPSigned::setSignature(const QString &signature) +{ + d_func()->signature = signature; +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/pgpsigned.h
Added
@@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_PGPSIGNED_H +#define JREEN_PGPSIGNED_H + +#include "stanzaextension.h" + +namespace Jreen +{ + +class PGPSignedPrivate; + +class JREEN_EXPORT PGPSigned : public Payload +{ + J_PAYLOAD(Jreen::PGPSigned) + Q_DECLARE_PRIVATE(PGPSigned) +public: + PGPSigned(const QString &signature = QString()); + ~PGPSigned(); + + QString signature() const; + void setSignature(const QString &signature); + +private: + QScopedPointer<PGPSignedPrivate> d_ptr; +}; + +} // namespace Jreen + +#endif // JREEN_PGPSIGNED_H
View file
libjreen-1.0.3.tar.bz2/src/pingfactory_p.h -> libjreen-1.1.0.tar.bz2/src/pingfactory_p.h
Changed
@@ -30,7 +30,7 @@ namespace Jreen { //overkill -class PingFactory : public PayloadFactory<Ping> +class JREEN_AUTOTEST_EXPORT PingFactory : public PayloadFactory<Ping> { public: PingFactory();
View file
libjreen-1.0.3.tar.bz2/src/presence_p.h -> libjreen-1.1.0.tar.bz2/src/presence_p.h
Changed
@@ -36,7 +36,10 @@ class PresencePrivate : public StanzaPrivate { public: - PresencePrivate() : StanzaPrivate(StanzaPresence) {} + PresencePrivate() + : StanzaPrivate(StanzaPresence), + subtype(Presence::Available), + priority(0) {} Presence::Type subtype; LangMap status; int priority;
View file
libjreen-1.0.3.tar.bz2/src/presencefactory.cpp -> libjreen-1.1.0.tar.bz2/src/presencefactory.cpp
Changed
@@ -35,16 +35,7 @@ PresenceFactory::PresenceFactory(Client *client) : StanzaFactory(client) { - m_depth = 0; m_state = AtNowhere; - clear(); -} - -void PresenceFactory::clear() -{ - m_status.clear(); - m_priority = 0; - m_subtype = Presence::Available; } int PresenceFactory::stanzaType() @@ -54,18 +45,15 @@ Stanza::Ptr PresenceFactory::createStanza() { - PresencePrivate *p = new PresencePrivate; - p->from = m_from; - p->to = m_to; - p->id = m_id; - p->subtype = m_subtype; - p->status = m_status; - p->priority = m_priority; - return Stanza::Ptr(new Presence(*p)); + return Stanza::Ptr(new Presence(*static_cast<PresencePrivate*>(m_stanza.take()))); } void PresenceFactory::serialize(Stanza *stanza, QXmlStreamWriter *writer) { + if (!StanzaPrivate::get(*stanza)->tokens.isEmpty()) { + StanzaFactory::serialize(stanza, writer); + return; + } Presence *presence = static_cast<Presence*>(stanza); if(presence->subtype() == Presence::Invalid) return; @@ -133,28 +121,29 @@ void PresenceFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) { - Q_UNUSED(uri); m_depth++; + if (m_depth == 1) + m_stanza.reset(new PresencePrivate); + StanzaFactory::handleStartElement(name, uri, attributes); + PresencePrivate *p = static_cast<PresencePrivate*>(m_stanza.data()); if (m_depth == 1) { - clear(); - parseAttributes(attributes); QStringRef type = attributes.value(QLatin1String("type")); if (type == QLatin1String("unavailable")) - m_subtype = Presence::Unavailable; + p->subtype = Presence::Unavailable; else if (type == QLatin1String("probe")) - m_subtype = Presence::Probe; + p->subtype = Presence::Probe; else if (type == QLatin1String("subscribe")) - m_subtype = Presence::Subscribe; + p->subtype = Presence::Subscribe; else if (type == QLatin1String("unsubscribe")) - m_subtype = Presence::Unsubscribe; + p->subtype = Presence::Unsubscribe; else if (type == QLatin1String("subscribed")) - m_subtype = Presence::Subscribe; + p->subtype = Presence::Subscribe; else if (type == QLatin1String("unsubscribed")) - m_subtype = Presence::Unsubscribe; + p->subtype = Presence::Unsubscribe; else if (type == QLatin1String("error")) - m_subtype = Presence::Error; + p->subtype = Presence::Error; else - m_subtype = Presence::Available; + p->subtype = Presence::Available; } else if(m_depth == 2) { if(name == QLatin1String("show")) m_state = AtShow; @@ -163,42 +152,39 @@ } else if(name == QLatin1String("status")) { m_state = AtStatus; - m_xmllang = attributes.value(QLatin1String("xml:lang")); + m_xmllang = attributes.value(QLatin1String("xml:lang")).toString(); } } } void PresenceFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) { + StanzaFactory::handleEndElement(name, uri); if (m_depth == 2) m_state = AtNowhere; m_depth--; - Q_UNUSED(name); - Q_UNUSED(uri); } void PresenceFactory::handleCharacterData(const QStringRef &text) { + StanzaFactory::handleCharacterData(text); if(m_depth == 2) { + PresencePrivate *p = static_cast<PresencePrivate*>(m_stanza.data()); if(m_state == AtShow) { -/* if(text == QLatin1String("available")) - m_type = Presence::Available; - else if(text == QLatin1String("unavailable")) - m_type = Presence::Unavailable; - else */if(text == QLatin1String("away")) - m_subtype = Presence::Away; + if(text == QLatin1String("away")) + p->subtype = Presence::Away; else if(text == QLatin1String("chat")) - m_subtype = Presence::Chat; + p->subtype = Presence::Chat; else if(text == QLatin1String("dnd")) - m_subtype = Presence::DND; + p->subtype = Presence::DND; else if(text == QLatin1String("xa")) - m_subtype = Presence::XA; + p->subtype = Presence::XA; } else if(m_state == AtPriority) { - m_priority = text.toString().toInt(); + p->priority = text.toString().toInt(); } else if(m_state == AtStatus) { - m_statusm_xmllang.toString() = text.toString(); + p->statusm_xmllang = text.toString(); } } }
View file
libjreen-1.0.3.tar.bz2/src/presencefactory_p.h -> libjreen-1.1.0.tar.bz2/src/presencefactory_p.h
Changed
@@ -33,7 +33,7 @@ namespace Jreen { -class PresenceFactory : public StanzaFactory +class JREEN_AUTOTEST_EXPORT PresenceFactory : public StanzaFactory { public: enum State { AtNowhere, AtShow, AtStatus,AtPriority }; @@ -46,13 +46,8 @@ void handleEndElement(const QStringRef &name, const QStringRef &uri); void handleCharacterData(const QStringRef &name); private: - void clear(); - int m_depth; - Presence::Type m_subtype; - int m_priority; - LangMap m_status; State m_state; - QStringRef m_xmllang; + QString m_xmllang; }; }
View file
libjreen-1.0.3.tar.bz2/src/privacyqueryfactory_p.h -> libjreen-1.1.0.tar.bz2/src/privacyqueryfactory_p.h
Changed
@@ -30,7 +30,7 @@ namespace Jreen { -class PrivacyQueryFactory : public PayloadFactory<PrivacyQuery> +class JREEN_AUTOTEST_EXPORT PrivacyQueryFactory : public PayloadFactory<PrivacyQuery> { public: PrivacyQueryFactory();
View file
libjreen-1.0.3.tar.bz2/src/privatexml_p.h -> libjreen-1.1.0.tar.bz2/src/privatexml_p.h
Changed
@@ -86,7 +86,7 @@ Type m_type; }; -class PrivateXmlQueryFactory : public PayloadFactory<PrivateXmlQuery> +class JREEN_AUTOTEST_EXPORT PrivateXmlQueryFactory : public PayloadFactory<PrivateXmlQuery> { public: PrivateXmlQueryFactory(Client *client);
View file
libjreen-1.0.3.tar.bz2/src/pubsubeventfactory_p.h -> libjreen-1.1.0.tar.bz2/src/pubsubeventfactory_p.h
Changed
@@ -33,7 +33,7 @@ { namespace PubSub { -class EventFactory : public PayloadFactory<Event> +class JREEN_AUTOTEST_EXPORT EventFactory : public PayloadFactory<Event> { public: EventFactory(QList<AbstractPayloadFactory*> &factories);
View file
libjreen-1.0.3.tar.bz2/src/pubsubpublishfactory.cpp -> libjreen-1.1.0.tar.bz2/src/pubsubpublishfactory.cpp
Changed
@@ -39,6 +39,7 @@ PublishFactory::PublishFactory(QList<AbstractPayloadFactory*> &factories) : m_factories(factories) { m_depth = 0; + m_factory = 0; m_state = AtNowhere; } @@ -65,7 +66,7 @@ if (m_depth == 1) { m_publish.reset(new Publish); } if (m_depth == 2 && name == QLatin1String("publish")) { - findFactory(attributes.value(QLatin1String("node"))); + m_factory = findFactory(attributes.value(QLatin1String("node"))); m_state = m_factory ? AtPublish : AtNowhere; } else if (m_depth == 3 && m_state == AtPublish && name == QLatin1String("item")) { m_state = AtItem; @@ -116,7 +117,7 @@ Logger::warning() << "Invalid stanza extension at PubSub::Publish"; return; } - writer->writeStartElement(QLatin1String("pusbsub")); + writer->writeStartElement(QLatin1String("pubsub")); writer->writeDefaultNamespace(NS_PUBSUB); writer->writeStartElement(QLatin1String("publish")); writer->writeAttribute(QLatin1String("node"), node);
View file
libjreen-1.0.3.tar.bz2/src/pubsubpublishfactory_p.h -> libjreen-1.1.0.tar.bz2/src/pubsubpublishfactory_p.h
Changed
@@ -33,7 +33,7 @@ { namespace PubSub { -class PublishFactory : public PayloadFactory<Publish> +class JREEN_AUTOTEST_EXPORT PublishFactory : public PayloadFactory<Publish> { public: PublishFactory(QList<AbstractPayloadFactory*> &factories);
View file
libjreen-1.0.3.tar.bz2/src/receiptfactory.cpp -> libjreen-1.1.0.tar.bz2/src/receiptfactory.cpp
Changed
@@ -35,7 +35,7 @@ static const char *receipt_strings = {"request","received"}; -class ReceiptFactoryPrivate +class JREEN_AUTOTEST_EXPORT ReceiptFactoryPrivate { public: Receipt::Type type;
View file
libjreen-1.0.3.tar.bz2/src/receiptfactory_p.h -> libjreen-1.1.0.tar.bz2/src/receiptfactory_p.h
Changed
@@ -28,8 +28,8 @@ namespace Jreen { -class ReceiptFactoryPrivate; -class ReceiptFactory : public PayloadFactory<Receipt> +class JREEN_AUTOTEST_EXPORT ReceiptFactoryPrivate; +class JREEN_AUTOTEST_EXPORT ReceiptFactory : public PayloadFactory<Receipt> { Q_DECLARE_PRIVATE(ReceiptFactory) public:
View file
libjreen-1.1.0.tar.bz2/src/registrationfeature.cpp
Added
@@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "registrationfeature_p.h" +#include "registrationmanager_p.h" + +namespace Jreen +{ + +#define NS_REGISTER QLatin1String("http://jabber.org/features/iq-register") + +RegistrationFeature::RegistrationFeature(RegistrationManager *manager) + : StreamFeature(RegistrationRequest), m_manager(manager), m_activatable(false) +{ +} + +int RegistrationFeature::priority() +{ + return 10; +} + +bool RegistrationFeature::isActivatable() +{ + return m_activatable; +} + +bool RegistrationFeature::activate() +{ + RegistrationManagerPrivate::get(m_manager)->handleConnection(); + return true; +} + +void RegistrationFeature::reset() +{ + m_activatable = false; +} + +bool RegistrationFeature::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(attributes); + return name == QLatin1String("register") && uri == NS_REGISTER; +} + +void RegistrationFeature::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(uri); + Q_UNUSED(attributes); + if (name == QLatin1String("register")) + m_activatable = true; +} + +void RegistrationFeature::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + Q_UNUSED(name); + Q_UNUSED(uri); +} + +void RegistrationFeature::handleCharacterData(const QStringRef &text) +{ + Q_UNUSED(text); +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/registrationfeature_p.h
Added
@@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_REGISTRATIONFEATURE_P_H +#define JREEN_REGISTRATIONFEATURE_P_H + +#include "streamfeature_p.h" + +namespace Jreen +{ + +class RegistrationManager; + +class RegistrationFeature : public StreamFeature +{ +public: + RegistrationFeature(RegistrationManager *manager); + + virtual int priority(); + virtual bool isActivatable(); + virtual bool activate(); + virtual void reset(); + virtual bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + virtual void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + virtual void handleEndElement(const QStringRef &name, const QStringRef &uri); + virtual void handleCharacterData(const QStringRef &text); + +private: + RegistrationManager *m_manager; + bool m_activatable; +}; + +} // namespace Jreen + +#endif // JREEN_REGISTRATIONFEATURE_P_H
View file
libjreen-1.1.0.tar.bz2/src/registrationmanager.cpp
Added
@@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "registrationmanager_p.h" +#include "registrationquery_p.h" +#include "registrationfeature_p.h" +#include "iqreply.h" +#include "iq_p.h" +#include "logger.h" +#include <QCoreApplication> +#include <QTimer> + +namespace Jreen +{ + +RegistrationData::RegistrationData() : d(new RegistrationDataPrivate) +{ +} + +RegistrationData::RegistrationData(const RegistrationData &data) : d(data.d) +{ +} + +RegistrationData::RegistrationData(const QSharedDataPointer<RegistrationDataPrivate> &data) : d(data) +{ +} + +RegistrationData &RegistrationData::operator =(const RegistrationData &data) +{ + d = data.d; + return *this; +} + +RegistrationData::~RegistrationData() +{ +} + +DataForm::Ptr RegistrationData::form() const +{ + return d->form; +} + +void RegistrationData::setForm(const DataForm::Ptr &form) +{ + d->form = form; +} + +bool RegistrationData::hasForm() const +{ + return !d->form.isNull(); +} + +QString RegistrationData::instructions() const +{ + return d->instructions; +} + +QString RegistrationData::fieldValue(FieldType type) const +{ + return d->values.value(type); +} + +// It's not good time for localization support yet + +//const char *registrationTranslations = { +// QT_TRANSLATE_NOOP("Jreen", "Username"), +// QT_TRANSLATE_NOOP("Jreen", "Familiar name of the user"), +// QT_TRANSLATE_NOOP("Jreen", "Password"), +// QT_TRANSLATE_NOOP("Jreen", "Full name"), +// QT_TRANSLATE_NOOP("Jreen", "Given name"), +// QT_TRANSLATE_NOOP("Jreen", "Family name"), +// QT_TRANSLATE_NOOP("Jreen", "Email"), +// QT_TRANSLATE_NOOP("Jreen", "Street"), +// QT_TRANSLATE_NOOP("Jreen", "Locality"), +// QT_TRANSLATE_NOOP("Jreen", "Region"), +// QT_TRANSLATE_NOOP("Jreen", "Postal code"), +// QT_TRANSLATE_NOOP("Jreen", "Phone number"), +// QT_TRANSLATE_NOOP("Jreen", "Web page url"), +// QT_TRANSLATE_NOOP("Jreen", "Birth date") +//}; + +//QString RegistrationData::fieldText(RegistrationData::FieldType type) const +//{ +// size_t count = sizeof(registrationTranslations) / sizeof(registrationTranslations0); +// if (type >= 0 && type < count) +// return QCoreApplication::translate("Jreen", registrationTranslationstype); +// return QString(); +//} + +bool RegistrationData::hasField(RegistrationData::FieldType type) const +{ + return (d->valuesFlags & (1 << type)); +} + +bool RegistrationData::hasFields() const +{ + return d->valuesFlags != 0; +} + +void RegistrationData::setFieldValue(RegistrationData::FieldType type, const QString &value) +{ + if (d->values.size() <= type) { + Logger::warning() << "Unkown RegistrationData::ValueType:" << type; + return; + } + d->valuesFlags |= (1 << type); + d->valuestype = value; +} + +QList<BitsOfBinary::Ptr> RegistrationData::bitsOfBinaries() const +{ + return d->bobs; +} + +void RegistrationManagerPrivate::requestInfo() +{ + ConnectionIQ iq(IQ::Get, service); + iq.addPayload(new RegistrationQuery); + sendIQ(iq, SLOT(_q_form_received(Jreen::IQ))); +} + +void RegistrationManagerPrivate::handleConnection() +{ + waitingForConnection = false; + while (!iqs.isEmpty()) { + QPair<IQ, QByteArray> iq = iqs.takeFirst(); + sendIQ(iq.first, iq.second); + } + if (!fieldsReceived) + requestInfo(); +} + +void RegistrationManagerPrivate::sendIQ(const IQ &iq, const char *slot) +{ + Q_Q(RegistrationManager); + if (waitingForConnection) { + iqs << qMakePair(iq, QByteArray(slot)); + } else { + IQReply *reply = client->send(iq); + QObject::connect(reply, SIGNAL(received(Jreen::IQ)), + q, slot); + } +} + +void RegistrationManagerPrivate::_q_form_received(const Jreen::IQ &iq) +{ + Q_Q(RegistrationManager); + fieldsReceived = true; + if (RegistrationQuery::Ptr query = iq.payload<RegistrationQuery>()) + emit q->formReceived(RegistrationData(query->data)); + else + emit q->error(iq.error()); +} + +void RegistrationManagerPrivate::_q_result_received(const Jreen::IQ &iq) +{ + Q_Q(RegistrationManager); + if (iq.error()) { + emit q->error(iq.error()); + } else { + QObject::disconnect(client, 0, q, 0); + for (int i = 0; i < configs.size(); ++i) { + Client::Feature feature = static_cast<Client::Feature>(i); + client->setFeatureConfig(feature, configsi); + } + if (feature) { + client->removeStreamFeature(feature); + delete feature; + feature = 0; + } + emit q->success(); + } +} + +void RegistrationManagerPrivate::_q_on_disconnect(Client::DisconnectReason reason) +{ + Q_Q(RegistrationManager); + waitingForConnection = true; + if (reason == Client::NoSupportedFeature + || reason == Client::NoEncryptionSupport + || reason == Client::NoCompressionSupport + || reason == Client::NoAuthorizationSupport) { + emit q->unsupported(); + } else { + QTimer::singleShot(0, client, SLOT(connectToServer())); + } +} + +RegistrationManager::RegistrationManager(const JID &service, Client *client) + : QObject(client), d_ptr(new RegistrationManagerPrivate(this)) +{ + Q_D(RegistrationManager); + d->service = service; + d->client = client; + d->feature = 0; +} + +RegistrationManager::~RegistrationManager() +{ +} + +void RegistrationManager::registerAtServer() +{ + Q_D(RegistrationManager); + d->fieldsReceived = false; + d->waitingForConnection = true; + d->feature = new RegistrationFeature(this); + connect(d->client, SIGNAL(disconnected(Jreen::Client::DisconnectReason)), + SLOT(_q_on_disconnect(Jreen::Client::DisconnectReason))); + d->client->setJID(d->service); + d->client->registerStreamFeature(d->feature); + d->configs.resize(3); + for (int i = 0; i < 3; ++i) { + Client::Feature feature = static_cast<Client::Feature>(i); + d->configsi = d->client->featureConfig(feature); + } + d->client->setFeatureConfig(Client::Authorization, Client::Disable); + d->client->connectToServer(); +} + +void RegistrationManager::registerAtService() +{ + Q_D(RegistrationManager); + d->waitingForConnection = false; + d->requestInfo(); +} + +void RegistrationManager::fetchFields() +{ + Q_D(RegistrationManager); + d->requestInfo(); +} + +void RegistrationManager::send(const Jreen::RegistrationData &data) +{ + Q_D(RegistrationManager); + ConnectionIQ iq(IQ::Set, d->service); + iq.addPayload(new RegistrationQuery(data)); + d->sendIQ(iq, SLOT(_q_result_received(Jreen::IQ))); +} + +} + +#include "moc_registrationmanager.cpp"
View file
libjreen-1.1.0.tar.bz2/src/registrationmanager.h
Added
@@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef REGISTRATIONMANAGER_H +#define REGISTRATIONMANAGER_H + +#include "dataform.h" +#include "error.h" +#include "bitsofbinary.h" +#include "iq.h" + +namespace Jreen +{ + +class RegistrationManager; +class RegistrationManagerPrivate; +class RegistrationDataPrivate; + +class JREEN_EXPORT RegistrationData +{ +public: + enum FieldType { + UsernameField, + NickField, + PasswordField, + FullNameField, + FirstNameField, + LastNameField, + EmailField, + AddressField, + CityField, + StateField, + ZipField, + PhoneField, + UrlField, + DateField, +// MiscField, +// TextField, +// KeyField, + LastFieldType = DateField + }; + + RegistrationData(); + RegistrationData(const RegistrationData &data); + RegistrationData &operator =(const RegistrationData &data); + ~RegistrationData(); + + DataForm::Ptr form() const; + void setForm(const DataForm::Ptr &form); + bool hasForm() const; + QString instructions() const; + QString fieldValue(FieldType type) const; + bool hasField(FieldType type) const; + bool hasFields() const; + void setFieldValue(FieldType type, const QString &value); + QList<Jreen::BitsOfBinary::Ptr> bitsOfBinaries() const; + +private: + RegistrationData(const QSharedDataPointer<RegistrationDataPrivate> &data); + + friend class RegistrationManager; + friend class RegistrationManagerPrivate; + friend class RegistrationDataPrivate; + QSharedDataPointer<RegistrationDataPrivate> d; +}; + +class JREEN_EXPORT RegistrationManager : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(RegistrationManager) +public: + RegistrationManager(const JID &service, Client *client); + ~RegistrationManager(); + +signals: + void formReceived(const Jreen::RegistrationData &data); + void error(const Jreen::Error::Ptr &error); + void success(); + void unsupported(); + +public slots: + void registerAtServer(); + void registerAtService(); + void fetchFields(); + void send(const Jreen::RegistrationData &data); + +private: + Q_PRIVATE_SLOT(d_func(), void _q_form_received(const Jreen::IQ &iq)) + Q_PRIVATE_SLOT(d_func(), void _q_result_received(const Jreen::IQ &iq)) + Q_PRIVATE_SLOT(d_func(), void _q_on_disconnect(Jreen::Client::DisconnectReason)) + QScopedPointer<RegistrationManagerPrivate> d_ptr; +}; + +} + +#endif // REGISTRATIONMANAGER_H
View file
libjreen-1.1.0.tar.bz2/src/registrationmanager_p.h
Added
@@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef REGISTRATIONMANAGER_P_H +#define REGISTRATIONMANAGER_P_H + +#include "registrationmanager.h" +#include "client.h" +#include <QQueue> + +namespace Jreen +{ + +class RegistrationFeature; +class RegistrationQuery; + +class RegistrationDataPrivate : public QSharedData +{ +public: + typedef QSharedDataPointer<RegistrationDataPrivate> Ptr; + + enum Flag { + Registered = 0x01, + Remove = 0x02 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + RegistrationDataPrivate() : valuesFlags(0) { values.resize(RegistrationData::LastFieldType + 1); } + RegistrationDataPrivate(const RegistrationDataPrivate &o) + : QSharedData(o), form(o.form), flags(o.flags), instructions(o.instructions), + valuesFlags(o.valuesFlags), values(o.values), bobs(o.bobs) {} + static Ptr get(const RegistrationData &data) { return data.d; } + + DataForm::Ptr form; + Flags flags; + QString instructions; + int valuesFlags; + QVector<QString> values; + QList<BitsOfBinary::Ptr> bobs; +}; + +class RegistrationManagerPrivate +{ + Q_DECLARE_PUBLIC(RegistrationManager) +public: + RegistrationManagerPrivate(RegistrationManager *q) : q_ptr(q), fieldsReceived(false), waitingForConnection(true) {} + + static RegistrationManagerPrivate *get(RegistrationManager *manager) { return manager->d_func(); } + void requestInfo(); + void handleConnection(); + void sendIQ(const Jreen::IQ &iq, const char *slot); + void _q_form_received(const Jreen::IQ &iq); + void _q_result_received(const Jreen::IQ &iq); + void _q_on_disconnect(Jreen::Client::DisconnectReason reason); + + RegistrationManager *q_ptr; + Client *client; + RegistrationFeature *feature; + bool fieldsReceived; + bool waitingForConnection; + QQueue<QPair<Jreen::IQ, QByteArray> > iqs; + QVector<Client::FeatureConfig> configs; + JID service; +}; + +} + +#endif // REGISTRATIONMANAGER_P_H
View file
libjreen-1.1.0.tar.bz2/src/registrationquery.cpp
Added
@@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "registrationquery_p.h" +#include "registrationmanager_p.h" + +namespace Jreen { + +RegistrationQuery::RegistrationQuery() : data(new RegistrationDataPrivate) +{ +} + +RegistrationQuery::RegistrationQuery(const RegistrationData &d) : data(RegistrationDataPrivate::get(d)) +{ +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/registrationquery_p.h
Added
@@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_REGISTRATIONQUERY_P_H +#define JREEN_REGISTRATIONQUERY_P_H + +#include "stanzaextension.h" +#include "dataform.h" +#include "registrationmanager_p.h" + +namespace Jreen { + +class RegistrationData; + +class RegistrationQuery : public Payload +{ + J_PAYLOAD(Jreen::RegistrationQuery) +public: + RegistrationQuery(); + RegistrationQuery(const RegistrationData &data); + + RegistrationDataPrivate::Ptr data; +}; + +} // namespace Jreen + +#endif // JREEN_REGISTRATIONQUERY_P_H
View file
libjreen-1.1.0.tar.bz2/src/registrationqueryfactory.cpp
Added
@@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#include "registrationqueryfactory_p.h" +#include "jstrings.h" + +#define NS_REGISTER QLatin1String("jabber:iq:register") + +namespace Jreen +{ + +const char *emptyNames = { + "registered", + "remove" +}; + +const char *valueNames = { + "username", + "nick", + "password", + "name", + "first", + "last", + "email", + "address", + "city", + "state", + "zip", + "phone", + "url", + "date" + "misc", + "text", + "key" +}; + + +RegistrationQueryFactory::RegistrationQueryFactory() : m_state(Nowhere), m_depth(0) +{ +} + +QStringList RegistrationQueryFactory::features() const +{ + return QStringList(); // << NS_REGISTER; +} + +bool RegistrationQueryFactory::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(attributes); + m_state = Nowhere; + m_depth = 0; + m_query.reset(new RegistrationQuery); + return name == QLatin1String("query") && uri == NS_REGISTER; +} + +void RegistrationQueryFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + ++m_depth; + if (m_depth == 2) { + if (m_formFactory.canParse(name, uri, attributes)) { + m_state = AtForm; + } else if (m_bobFactory.canParse(name, uri, attributes)) { + m_state = AtBob; + } else if (name == QLatin1String("instructions")) { + m_state = AtInstructions; + } else { + RegistrationDataPrivate::Flag flag = strToFlag<RegistrationDataPrivate::Flag>(name, emptyNames); + if (flag != -1) { + m_query->data->flags |= flag; + return; + } + int index = strToEnum(name, valueNames); + if (index != -1) { + m_query->data->valuesFlags |= (1 << index); + m_state = static_cast<State>(AtValue + index); + return; + } + } + } + if (m_state == AtForm) + m_formFactory.handleStartElement(name, uri, attributes); + else if (m_state == AtBob) + m_bobFactory.handleStartElement(name, uri, attributes); +} + +void RegistrationQueryFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + if (m_state == AtForm) + m_formFactory.handleEndElement(name, uri); + else if (m_state == AtBob) + m_bobFactory.handleEndElement(name, uri); + if (m_depth == 2) { + if (m_state == AtForm) + m_query->data->form = m_formFactory.createPayload().staticCast<DataForm>(); + else if (m_state == AtBob) + m_query->data->bobs << m_bobFactory.createPayload().staticCast<BitsOfBinary>(); + m_state = Nowhere; + } + --m_depth; +} + +void RegistrationQueryFactory::handleCharacterData(const QStringRef &text) +{ + if (m_state == AtForm) + m_formFactory.handleCharacterData(text); + else if (m_state == AtBob) + m_bobFactory.handleCharacterData(text); + else if (m_state == AtInstructions) + m_query->data->instructions = text.toString(); + else if (m_state >= AtValue) + m_query->data->valuesm_state - AtValue = text.toString(); +} + +void RegistrationQueryFactory::serialize(Payload *extension, QXmlStreamWriter *writer) +{ + RegistrationQuery *query = se_cast<RegistrationQuery*>(extension); + writer->writeStartElement(QLatin1String("query")); + writer->writeDefaultNamespace(NS_REGISTER); + for (uint i = 0; i < sizeof(emptyNames) / sizeof(emptyNames0); ++i) { + if (query->data->flags & (1 << i)) + writer->writeEmptyElement(QLatin1String(emptyNamesi)); + } + for (int i = 0; i < query->data->values.size(); ++i) { + if (query->data->valuesFlags & (1 << i)) + writer->writeTextElement(QLatin1String(valueNamesi), query->data->valuesi); + } + if (query->data->form) + m_formFactory.serialize(query->data->form.data(), writer); + writer->writeEndElement(); +} + +Payload::Ptr RegistrationQueryFactory::createPayload() +{ + return Payload::Ptr(m_query.take()); +} + +} // namespace Jreen
View file
libjreen-1.1.0.tar.bz2/src/registrationqueryfactory_p.h
Added
@@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Jreen +** +** Copyright © 2012 Ruslan Nigmatullin <euroelessar@yandex.ru> +** +***************************************************************************** +** +** $JREEN_BEGIN_LICENSE$ +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +** See the GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see http://www.gnu.org/licenses/. +** $JREEN_END_LICENSE$ +** +****************************************************************************/ + +#ifndef JREEN_REGISTRATIONQUERYFACTORY_P_H +#define JREEN_REGISTRATIONQUERYFACTORY_P_H + +#include "registrationquery_p.h" +#include "dataformfactory_p.h" +#include "bitsofbinaryfactory_p.h" + +namespace Jreen +{ + +class JREEN_AUTOTEST_EXPORT RegistrationQueryFactory : public PayloadFactory<RegistrationQuery> +{ +public: + RegistrationQueryFactory(); + QStringList features() const; + bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleEndElement(const QStringRef &name, const QStringRef &uri); + void handleCharacterData(const QStringRef &text); + void serialize(Payload *extension, QXmlStreamWriter *writer); + Payload::Ptr createPayload(); +private: + enum State { + Nowhere, + AtForm, + AtBob, + AtInstructions, + AtValue + } m_state; + int m_depth; + DataFormFactory m_formFactory; + BitsOfBinaryFactory m_bobFactory; + QScopedPointer<RegistrationQuery> m_query; +}; + +} // namespace Jreen + +#endif // JREEN_REGISTRATIONQUERYFACTORY_P_H
View file
libjreen-1.0.3.tar.bz2/src/saslfeature.cpp -> libjreen-1.1.0.tar.bz2/src/saslfeature.cpp
Changed
@@ -26,19 +26,22 @@ #include "saslfeature_p.h" #include "client_p.h" #include <QUrl> +#include <QCoreApplication> #include "logger.h" #ifdef HAVE_SIMPLESASL # include "../3rdparty/simplesasl/simplesasl.h" #endif +#define NS_SASL QLatin1String("urn:ietf:params:xml:ns:xmpp-sasl") + namespace Jreen { SASLFeature::SASLFeature() : StreamFeature(SASL) { QCA::init(); - QCA::setAppName("qutim"); + QCA::setAppName(QCoreApplication::applicationName()); m_depth = 0; m_isSupported = QCA::isSupported("sasl"); #ifdef HAVE_SIMPLESASL @@ -83,7 +86,7 @@ return false; Q_UNUSED(name); Q_UNUSED(attributes); - return uri == QLatin1String("urn:ietf:params:xml:ns:xmpp-sasl"); + return uri == NS_SASL; } void SASLFeature::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) @@ -147,9 +150,9 @@ void SASLFeature::onClientStarted(bool init, const QByteArray &data) { - QXmlStreamWriter *writer = ClientPrivate::get(m_client)->writer; + QXmlStreamWriter *writer = m_info->writer(); writer->writeStartElement(QLatin1String("auth")); - writer->writeDefaultNamespace(QLatin1String("urn:ietf:params:xml:ns:xmpp-sasl")); + writer->writeDefaultNamespace(NS_SASL); writer->writeAttribute(QLatin1String("mechanism"), m_sasl->mechanism()); if (init) writer->writeCharacters(QString::fromLatin1(data.toBase64())); @@ -158,9 +161,9 @@ void SASLFeature::onNextStep(const QByteArray &data) { - QXmlStreamWriter *writer = ClientPrivate::get(m_client)->writer; + QXmlStreamWriter *writer = m_info->writer(); writer->writeStartElement(QLatin1String("response")); - writer->writeDefaultNamespace(QLatin1String("urn:ietf:params:xml:ns:xmpp-sasl")); + writer->writeDefaultNamespace(NS_SASL); writer->writeCharacters(QString::fromLatin1(data.toBase64())); writer->writeEndElement(); } @@ -173,13 +176,17 @@ m_sasl->setUsername(m_info->jid().node()); if (params.canSendRealm()) m_sasl->setRealm(m_info->jid().domain()); - if (params.canSendAuthzid() && m_info->jid().domain() != QLatin1String("chat.facebook.com")) - m_sasl->setAuthzid(m_info->jid().bare()); + // ??? + // Why SASL tells me that I can send Authzid? + /*if (params.canSendAuthzid() && m_info->jid().domain() != QLatin1String("chat.facebook.com")) + m_sasl->setAuthzid(m_info->jid().bare());*/ m_sasl->continueAfterParams(); } void SASLFeature::onAuthCheck(const QString &user, const QString &authzid) { + Q_UNUSED(user); + Q_UNUSED(authzid); m_sasl->continueAfterAuthCheck(); }
View file
libjreen-1.0.3.tar.bz2/src/sessionfeature.cpp -> libjreen-1.1.0.tar.bz2/src/sessionfeature.cpp
Changed
@@ -41,7 +41,7 @@ SessionQuery() {} }; -class SessionQueryFactory : public PayloadFactory<SessionQuery> +class JREEN_AUTOTEST_EXPORT SessionQueryFactory : public PayloadFactory<SessionQuery> { public: SessionQueryFactory() {}
View file
libjreen-1.0.3.tar.bz2/src/softwareversionfactory.cpp -> libjreen-1.1.0.tar.bz2/src/softwareversionfactory.cpp
Changed
@@ -37,7 +37,7 @@ static const char *query_strings = {"name","version","os"}; -class SoftwareVersionFactoryPrivate +class JREEN_AUTOTEST_EXPORT SoftwareVersionFactoryPrivate { public: int depth;
View file
libjreen-1.0.3.tar.bz2/src/softwareversionfactory_p.h -> libjreen-1.1.0.tar.bz2/src/softwareversionfactory_p.h
Changed
@@ -28,8 +28,8 @@ namespace Jreen { -class SoftwareVersionFactoryPrivate; -class SoftwareVersionFactory : public PayloadFactory<SoftwareVersion> +class JREEN_AUTOTEST_EXPORT SoftwareVersionFactoryPrivate; +class JREEN_AUTOTEST_EXPORT SoftwareVersionFactory : public PayloadFactory<SoftwareVersion> { Q_DECLARE_PRIVATE(SoftwareVersionFactory) public:
View file
libjreen-1.0.3.tar.bz2/src/stanza.cpp -> libjreen-1.1.0.tar.bz2/src/stanza.cpp
Changed
@@ -94,6 +94,11 @@ d_ptr->extensions.clear(); } +void Stanza::removePayload(int id) +{ + d_ptr->extensions.remove(id); +} + Error::Ptr Stanza::error() const { return payload<Error>();
View file
libjreen-1.0.3.tar.bz2/src/stanza.h -> libjreen-1.1.0.tar.bz2/src/stanza.h
Changed
@@ -58,12 +58,23 @@ { addExtension(Payload::Ptr(se)); } PayloadList payloads() const; template< class T > + QList<typename T::Ptr> payloads() const + { + QList<typename T::Ptr> list; + foreach (const Payload::Ptr &payload, payloads().values(T::staticPayloadType())) + list << payload.staticCast<T>(); + return list; + } + template< class T > inline const QSharedPointer<T> payload() const - { return qSharedPointerCast<T>(payloads().value(reinterpret_cast<T*>(0)->staticPayloadType())); } + { return qSharedPointerCast<T>(payloads().value(T::staticPayloadType())); } template< class T > inline bool containsPayload() const - { return payloads().contains(reinterpret_cast<T*>(0)->staticPayloadType()); } + { return payloads().contains(T::staticPayloadType()); } void removePayloads(); + template< class T > + inline void removePayload() { removePayload(T::staticPayloadType()); } + void removePayload(int id); Error::Ptr error() const; protected: Stanza(StanzaPrivate &);
View file
libjreen-1.0.3.tar.bz2/src/stanza_p.h -> libjreen-1.1.0.tar.bz2/src/stanza_p.h
Changed
@@ -50,11 +50,48 @@ StanzaMessage, StanzaSubscription }; + struct Token + { + enum Type { + StartElement, + EndElement, + Characters + }; + Token(Type t) : type(t) {} + + Type type; + }; + + struct StartToken : public Token + { + StartToken() : Token(StartElement) {} + + QStringRef name; + QStringRef uri; + QXmlStreamAttributes attributes; + }; + + struct EndToken : public Token + { + EndToken() : Token(EndElement) {} + }; + + struct CharactersToken : public Token + { + CharactersToken() : Token(Characters) {} + + QStringRef text; + }; StanzaPrivate(Type t) : type(t) { ref = 1; } + ~StanzaPrivate() + { + qDeleteAll(tokens); + } + void addExtensions(QXmlStreamWriter *writer) const { Q_UNUSED(writer); @@ -79,6 +116,8 @@ JID to; QString id; PayloadList extensions; + QList<Token*> tokens; + QString buffer; }; }
View file
libjreen-1.0.3.tar.bz2/src/stanzaextension.cpp -> libjreen-1.1.0.tar.bz2/src/stanzaextension.cpp
Changed
@@ -29,6 +29,7 @@ { typedef QHash<QByteArray, int> ByteArrayHash; Q_GLOBAL_STATIC(ByteArrayHash, seClassHash) +Q_GLOBAL_STATIC(QVector<QByteArray>, seClassVector) Payload::Payload() { @@ -42,11 +43,23 @@ { QByteArray t = type; int id = seClassHash()->value(t, seClassHash()->size()); - if (id == seClassHash()->size()) - seClassHash()->insert(t, id); + if (id == seClassHash()->size()) { + ByteArrayHash::Iterator it = seClassHash()->insert(t, id); + seClassVector()->append(it.key()); + } return id; } +const char *Payload::payloadName(int type) +{ + return seClassVector()->value(type).constData(); +} + +const char *Payload::payloadName() const +{ + return payloadName(payloadType()); +} + AbstractPayloadFactory::AbstractPayloadFactory() { }
View file
libjreen-1.0.3.tar.bz2/src/stanzaextension.h -> libjreen-1.1.0.tar.bz2/src/stanzaextension.h
Changed
@@ -52,8 +52,10 @@ virtual ~Payload(); static int registerPayloadType(const char *type); + static const char *payloadName(int type); virtual int payloadType() const = 0; + const char *payloadName() const; }; typedef QMultiMap<int, Payload::Ptr> PayloadList; @@ -73,7 +75,7 @@ typedef QMap<int, AbstractPayloadFactory*> PayloadFactoryMap; template <typename Extension> -class PayloadFactory : public AbstractPayloadFactory +class JREEN_AUTOTEST_EXPORT PayloadFactory : public AbstractPayloadFactory { Q_DISABLE_COPY(PayloadFactory) public: @@ -108,12 +110,18 @@ } template <typename T> -Q_INLINE_TEMPLATE T se_cast(Payload *se) +Q_INLINE_TEMPLATE T payload_cast(Payload *se) { if (se && reinterpret_cast<T>(0)->staticPayloadType() == se->payloadType()) return static_cast<T>(se); return 0; } + +template <typename T> +Q_INLINE_TEMPLATE T se_cast(Payload *se) +{ + return payload_cast<T>(se); +} } #define J_PAYLOAD(Class) \
View file
libjreen-1.0.3.tar.bz2/src/stanzafactory.cpp -> libjreen-1.1.0.tar.bz2/src/stanzafactory.cpp
Changed
@@ -26,33 +26,108 @@ #include "stanzafactory_p.h" #include "client_p.h" #include "logger.h" +#include <QStack> namespace Jreen { StanzaFactory::StanzaFactory(Client *client) : m_client(client) { + m_depth = 0; } StanzaFactory::~StanzaFactory() { } -void StanzaFactory::parseAttributes(const QXmlStreamAttributes &attributes) +void StanzaFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) { - m_from = attributes.value(QLatin1String("from")).toString(); - m_to = attributes.value(QLatin1String("to")).toString(); - m_id = attributes.value(QLatin1String("id")).toString(); + while (!m_stanza->tokens.isEmpty() && m_stanza->tokens.last()->type == StanzaPrivate::Token::Characters) + delete m_stanza->tokens.takeLast(); + StanzaPrivate::StartToken *token = new StanzaPrivate::StartToken; + token->name = name.appendTo(&m_stanza->buffer); + token->uri = uri.appendTo(&m_stanza->buffer); + token->attributes = attributes; + m_stanza->tokens << token; + + if (m_depth == 1) { + m_stanza->from = attributes.value(QLatin1String("from")).toString(); + m_stanza->to = attributes.value(QLatin1String("to")).toString(); + m_stanza->id = attributes.value(QLatin1String("id")).toString(); + } else if (m_depth == 2) { + foreach (AbstractPayloadFactory *factory, ClientPrivate::get(m_client)->factories) { + if (factory->canParse(name, uri, attributes)) + m_parsers.append(factory); + } + } + for (int i = 0; i < m_parsers.size(); i++) + m_parsers.at(i)->handleStartElement(name, uri, attributes); +} + +void StanzaFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + for (int i = 0; i < m_parsers.size(); i++) + m_parsers.at(i)->handleEndElement(name, uri); + m_stanza->tokens << new StanzaPrivate::EndToken; + if (m_depth == 2) { + for (int i = 0; i < m_parsers.size(); i++) { + AbstractPayloadFactory *parser = static_cast<AbstractPayloadFactory*>(m_parsers.at(i)); + Payload::Ptr payload = parser->createPayload(); + if (payload.isNull()) + qFatal("Payload is null from %s", Payload::payloadName(parser->payloadType())); + m_stanza->extensions.insert(payload->payloadType(), payload); + } + m_parsers.clear(); + } +} + +void StanzaFactory::handleCharacterData(const QStringRef &text) +{ + for (int i = 0; i < m_parsers.size(); i++) + m_parsers.at(i)->handleCharacterData(text); + if (!m_stanza->tokens.isEmpty() && m_stanza->tokens.last()->type == StanzaPrivate::Token::EndElement) + return; + StanzaPrivate::CharactersToken *token = new StanzaPrivate::CharactersToken; + token->text = text.appendTo(&m_stanza->buffer); + m_stanza->tokens << token; +} + +void StanzaFactory::serialize(Stanza *stanza, QXmlStreamWriter *writer) +{ + StanzaPrivate *p = StanzaPrivate::get(*stanza); + QString namespaceUri = QLatin1String("jabber:client"); + QStack<QStringRef> uries; + for (int i = 0; i < p->tokens.size(); ++i) { + StanzaPrivate::Token * const token = p->tokens.at(i); + if (token->type == StanzaPrivate::Token::StartElement) { + StanzaPrivate::StartToken * const startToken = static_cast<StanzaPrivate::StartToken*>(token); + writer->writeStartElement(startToken->name.toString()); + QStringRef currentUri = (i == 0) ? QStringRef(&namespaceUri) : startToken->uri; + if (uries.isEmpty() || uries.top() != currentUri) + writer->writeDefaultNamespace(startToken->uri.toString()); + uries.push(currentUri); + writer->writeAttributes(startToken->attributes); + } else if (token->type == StanzaPrivate::Token::Characters) { + StanzaPrivate::CharactersToken * const charachtersToken = static_cast<StanzaPrivate::CharactersToken*>(token); + writer->writeCharacters(charachtersToken->text.toString()); + } else if (token->type == StanzaPrivate::Token::EndElement) { + writer->writeEndElement(); + uries.pop(); + } else { + Q_ASSERT(!"Unknown token type"); + } + } } void StanzaFactory::writeAttributes(Stanza *stanza, QXmlStreamWriter *writer) { - if(stanza->from().isValid()) - writer->writeAttribute(QLatin1String("from"), stanza->from()); - if(stanza->to().isValid()) - writer->writeAttribute(QLatin1String("to"), stanza->to()); - if(!stanza->id().isEmpty()) - writer->writeAttribute(QLatin1String("id"), stanza->id()); - writer->writeAttribute(QLatin1String("xmlns"), QLatin1String("jabber:client")); + StanzaPrivate *p = StanzaPrivate::get(*stanza); + if (p->from.isValid()) + writer->writeAttribute(QLatin1String("from"), p->from); + if (p->to.isValid()) + writer->writeAttribute(QLatin1String("to"), p->to); + if (!p->id.isEmpty()) + writer->writeAttribute(QLatin1String("id"), p->id); + writer->writeDefaultNamespace(QLatin1String("jabber:client")); } void StanzaFactory::writePayloads(Stanza *stanza, QXmlStreamWriter *writer)
View file
libjreen-1.0.3.tar.bz2/src/stanzafactory_p.h -> libjreen-1.1.0.tar.bz2/src/stanzafactory_p.h
Changed
@@ -26,30 +26,36 @@ #ifndef STANZAFACTORY_H #define STANZAFACTORY_H -#include "stanza.h" +#include "stanza_p.h" #include "langmap.h" #include <QXmlStreamAttributes> +#include <QStack> namespace Jreen { -class StanzaFactory : public XmlStreamFactory<Stanza> +class JREEN_AUTOTEST_EXPORT StanzaFactory : public XmlStreamFactory<Stanza> { public: StanzaFactory(Client *client); virtual ~StanzaFactory(); + + void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleEndElement(const QStringRef &name, const QStringRef &uri); + void handleCharacterData(const QStringRef &name); + virtual int stanzaType() = 0; virtual Stanza::Ptr createStanza() = 0; + void serialize(Stanza *stanza, QXmlStreamWriter *writer); protected: - void parseAttributes(const QXmlStreamAttributes &attributes); void writeAttributes(Stanza *stanza, QXmlStreamWriter *writer); void writePayloads(Stanza *stanza, QXmlStreamWriter *writer); void writeEscapedString(const QString &str, QXmlStreamWriter *writer); void writeLangMap(const QString &tag, const LangMap &map,QXmlStreamWriter *writer); //may be move to XmlStreamFactory? - JID m_from; - JID m_to; - QString m_id; + int m_depth; + QScopedPointer<StanzaPrivate> m_stanza; Client *m_client; + QStack<XmlStreamParser*> m_parsers; }; }
View file
libjreen-1.0.3.tar.bz2/src/streamfeature_p.h -> libjreen-1.1.0.tar.bz2/src/streamfeature_p.h
Changed
@@ -69,12 +69,13 @@ public: enum Type { - SecurityLayer, - CompressionLayer, - SASL, - SimpleAuthorization, - Custom, - Invalid + SecurityLayer = 0, + CompressionLayer = 0x10, + RegistrationRequest = 0x20, + SASL = 0x100, + SimpleAuthorization = 0x1000, + Custom = 0x10000, + Invalid = -1 }; StreamFeature(Type type) : m_info(0), m_client(0), m_type(type) {} virtual ~StreamFeature() {} @@ -96,6 +97,6 @@ } Q_DECLARE_OPERATORS_FOR_FLAGS(Jreen::StreamInfo::CompletedFlags) -Q_DECLARE_INTERFACE(Jreen::StreamFeature,"org.qutim.JReen.StreamFeature"); +Q_DECLARE_INTERFACE(Jreen::StreamFeature, "org.qutim.Jreen.StreamFeature") #endif // STREAMFEATURE_H
View file
libjreen-1.0.3.tar.bz2/src/tlsfeature.cpp -> libjreen-1.1.0.tar.bz2/src/tlsfeature.cpp
Changed
@@ -29,6 +29,7 @@ #include "client.h" #include <QXmlStreamWriter> #include "logger.h" +#include <QCoreApplication> #define NS_TLS QLatin1String("urn:ietf:params:xml:ns:xmpp-tls") @@ -38,7 +39,7 @@ TLSFeature::TLSFeature() : StreamFeature(SecurityLayer) { QCA::init(); - QCA::setAppName("qutim"); + QCA::setAppName(QCoreApplication::applicationName()); m_required = false; m_available = false; m_hasTls = QCA::isSupported("tls");
View file
libjreen-1.0.3.tar.bz2/src/tunefactory_p.h -> libjreen-1.1.0.tar.bz2/src/tunefactory_p.h
Changed
@@ -31,7 +31,7 @@ namespace Jreen { - class TuneFactory : public PayloadFactory<Tune> + class JREEN_AUTOTEST_EXPORT TuneFactory : public PayloadFactory<Tune> { public: TuneFactory();
View file
libjreen-1.0.3.tar.bz2/src/util.cpp -> libjreen-1.1.0.tar.bz2/src/util.cpp
Changed
@@ -119,32 +119,25 @@ return date_time.toUTC().toString(FULLZ_STAMP_STR); } -QByteArray Util::randomHash( /*const JID &jid*/ ) +QByteArray Util::randomHash() { -// Holy shit... -// QCryptographicHash hash(QCryptographicHash::Sha1); -// qptrdiff temp = QDateTime::currentDateTime().toTime_t(); -// QByteArray data; -// data.append(jid.full().toUtf8()); -// data.append('\0'); -// for(uint i = 0; i < sizeof(qptrdiff); i++, temp /= 0x100) -// data.append(temp % 0x100); -// data.append('\0'); -// temp = reinterpret_cast<qptrdiff>(&jid); -// for(uint i = 0; i < sizeof(qptrdiff); i++, temp /= 0x100) -// data.append(temp % 0x100); -// hash.addData(data); -// data.append('\0'); -// temp = qrand(); -// for(uint i = 0; i < sizeof(qptrdiff); i++, temp /= 0x100) -// data.append(temp % 0x100); -// hash.addData(data); -// return QLatin1String(hash.result().toHex()); -// Nobody whould find a differ qint32 buf5; for (int i = 0; i < 5; i++) bufi = qrand(); - return QByteArray(reinterpret_cast<char*>(buf), sizeof(buf)).toHex(); + return QByteArray::fromRawData(reinterpret_cast<char*>(buf), sizeof(buf)).toHex(); +} + +QString Util::randomStringHash(int length) +{ + QString str(length, Qt::Uninitialized); + for (int i = 0; i < length; ++i) { + int c = qrand() % (10 + 26); + if (c < 10) + stri = QLatin1Char('0' + c); + else + stri = QLatin1Char('a' + c - 10); + } + return str; } }
View file
libjreen-1.0.3.tar.bz2/src/util.h -> libjreen-1.1.0.tar.bz2/src/util.h
Changed
@@ -41,6 +41,8 @@ JREEN_EXPORT QString toStamp(const QDate &date); JREEN_EXPORT QString toStamp(const QDateTime &date_time); JREEN_EXPORT QByteArray randomHash(); +JREEN_EXPORT QString randomStringHash(int len); + inline int log2(register uint n) { register int pos = 0;
View file
libjreen-1.0.3.tar.bz2/src/vcardfactory.cpp -> libjreen-1.1.0.tar.bz2/src/vcardfactory.cpp
Changed
@@ -406,7 +406,7 @@ str = stringstype; } -class VCardFactoryPrivate +class JREEN_AUTOTEST_EXPORT VCardFactoryPrivate { public: void clear(); @@ -447,7 +447,7 @@ Payload::Ptr VCardFactory::createPayload() { Q_D(VCardFactory); - return Payload::Ptr(d->vcard ? new VCard(*d->vcard.take()) : 0); //here is segfault + return Payload::Ptr(new VCard(*d->vcard.take())); } QStringList VCardFactory::features() const
View file
libjreen-1.0.3.tar.bz2/src/vcardfactory_p.h -> libjreen-1.1.0.tar.bz2/src/vcardfactory_p.h
Changed
@@ -30,7 +30,7 @@ #include <QPair> namespace Jreen { -class VCardFactoryPrivate; +class JREEN_AUTOTEST_EXPORT VCardFactoryPrivate; class AbstractStructureParser : public XmlStreamParser { @@ -97,7 +97,7 @@ TPrivate m_data; }; -class VCardFactory : public PayloadFactory<VCard> +class JREEN_AUTOTEST_EXPORT VCardFactory : public PayloadFactory<VCard> { Q_DECLARE_PRIVATE(VCardFactory) public:
View file
libjreen-1.0.3.tar.bz2/src/vcardupdatefactory_p.h -> libjreen-1.1.0.tar.bz2/src/vcardupdatefactory_p.h
Changed
@@ -29,7 +29,7 @@ namespace Jreen { -class VCardUpdateFactory : public PayloadFactory<VCardUpdate> +class JREEN_AUTOTEST_EXPORT VCardUpdateFactory : public PayloadFactory<VCardUpdate> { public: VCardUpdateFactory();
View file
libjreen-1.0.3.tar.bz2/src/zlibcompressionfeature.cpp -> libjreen-1.1.0.tar.bz2/src/zlibcompressionfeature.cpp
Changed
@@ -27,6 +27,9 @@ #include "zlibdatastream_p.h" #include <QXmlStreamWriter> +#define NS_COMPRESS_FEATURE QLatin1String("http://jabber.org/features/compress") +#define NS_COMPRESS_PROTOCOL QLatin1String("http://jabber.org/protocol/compress") + namespace Jreen { ZLibCompressionFeature::ZLibCompressionFeature() : StreamFeature(CompressionLayer) @@ -45,7 +48,7 @@ { Q_UNUSED(name); Q_UNUSED(attributes); - return uri == QLatin1String("http://jabber.org/features/compress") || uri == QLatin1String("http://jabber.org/protocol/compress"); + return uri == NS_COMPRESS_FEATURE || uri == NS_COMPRESS_PROTOCOL; } void ZLibCompressionFeature::handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) @@ -90,7 +93,7 @@ { QXmlStreamWriter *writer = m_info->writer(); writer->writeStartElement(QLatin1String("compress")); - writer->writeDefaultNamespace(QLatin1String("http://jabber.org/protocol/compress")); + writer->writeDefaultNamespace(NS_COMPRESS_PROTOCOL); writer->writeTextElement(QLatin1String("method"), QLatin1String("zlib")); writer->writeEndElement(); return true;
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.