From deb9d6cb53057ca8b90d10d6a3bdc5dcfd1b3ee4 Mon Sep 17 00:00:00 2001 From: Jeremy Lainé Date: Wed, 8 Feb 2012 12:51:15 +0000 Subject: move files common to client/server into "base" --- src/QXmppArchiveIq.cpp | 572 -------- src/QXmppArchiveIq.h | 249 ---- src/QXmppBindIq.cpp | 90 -- src/QXmppBindIq.h | 60 - src/QXmppBookmarkSet.cpp | 232 --- src/QXmppBookmarkSet.h | 101 -- src/QXmppByteStreamIq.cpp | 183 --- src/QXmppByteStreamIq.h | 97 -- src/QXmppCodec.cpp | 1218 ---------------- src/QXmppCodec.h | 192 --- src/QXmppConstants.cpp | 75 - src/QXmppConstants.h | 74 - src/QXmppDataForm.cpp | 448 ------ src/QXmppDataForm.h | 140 -- src/QXmppDiscoveryIq.cpp | 300 ---- src/QXmppDiscoveryIq.h | 117 -- src/QXmppElement.cpp | 241 ---- src/QXmppElement.h | 77 - src/QXmppEntityTimeIq.cpp | 90 -- src/QXmppEntityTimeIq.h | 56 - src/QXmppGlobal.cpp | 34 - src/QXmppGlobal.h | 43 - src/QXmppIbbIq.cpp | 169 --- src/QXmppIbbIq.h | 105 -- src/QXmppIq.cpp | 147 -- src/QXmppIq.h | 73 - src/QXmppJingleIq.cpp | 848 ----------- src/QXmppJingleIq.h | 330 ----- src/QXmppLogger.cpp | 245 ---- src/QXmppLogger.h | 169 --- src/QXmppMessage.cpp | 417 ------ src/QXmppMessage.h | 123 -- src/QXmppMucIq.cpp | 300 ---- src/QXmppMucIq.h | 152 -- src/QXmppNonSASLAuth.cpp | 106 -- src/QXmppNonSASLAuth.h | 61 - src/QXmppPacket.cpp | 34 - src/QXmppPacket.h | 48 - src/QXmppPingIq.cpp | 47 - src/QXmppPingIq.h | 40 - src/QXmppPresence.cpp | 510 ------- src/QXmppPresence.h | 176 --- src/QXmppPubSubIq.cpp | 253 ---- src/QXmppPubSubIq.h | 108 -- src/QXmppRosterIq.cpp | 253 ---- src/QXmppRosterIq.h | 107 -- src/QXmppRpcIq.cpp | 443 ------ src/QXmppRpcIq.h | 130 -- src/QXmppRtpChannel.cpp | 1042 -------------- src/QXmppRtpChannel.h | 289 ---- src/QXmppSaslAuth.cpp | 214 --- src/QXmppSaslAuth.h | 72 - src/QXmppSessionIq.cpp | 44 - src/QXmppSessionIq.h | 49 - src/QXmppSocks.cpp | 345 ----- src/QXmppSocks.h | 81 -- src/QXmppStanza.cpp | 436 ------ src/QXmppStanza.h | 162 --- src/QXmppStream.cpp | 259 ---- src/QXmppStream.h | 92 -- src/QXmppStreamFeatures.cpp | 222 --- src/QXmppStreamFeatures.h | 76 - src/QXmppStreamInitiationIq.cpp | 106 -- src/QXmppStreamInitiationIq.h | 69 - src/QXmppStun.cpp | 2581 ---------------------------------- src/QXmppStun.h | 440 ------ src/QXmppUtils.cpp | 339 ----- src/QXmppUtils.h | 66 - src/QXmppVCardIq.cpp | 310 ---- src/QXmppVCardIq.h | 105 -- src/QXmppVersionIq.cpp | 111 -- src/QXmppVersionIq.h | 62 - src/base/QXmppArchiveIq.cpp | 572 ++++++++ src/base/QXmppArchiveIq.h | 249 ++++ src/base/QXmppBindIq.cpp | 90 ++ src/base/QXmppBindIq.h | 60 + src/base/QXmppBookmarkSet.cpp | 232 +++ src/base/QXmppBookmarkSet.h | 101 ++ src/base/QXmppByteStreamIq.cpp | 183 +++ src/base/QXmppByteStreamIq.h | 97 ++ src/base/QXmppCodec.cpp | 1218 ++++++++++++++++ src/base/QXmppCodec.h | 192 +++ src/base/QXmppConstants.cpp | 75 + src/base/QXmppConstants.h | 74 + src/base/QXmppDataForm.cpp | 448 ++++++ src/base/QXmppDataForm.h | 140 ++ src/base/QXmppDiscoveryIq.cpp | 300 ++++ src/base/QXmppDiscoveryIq.h | 117 ++ src/base/QXmppElement.cpp | 241 ++++ src/base/QXmppElement.h | 77 + src/base/QXmppEntityTimeIq.cpp | 90 ++ src/base/QXmppEntityTimeIq.h | 56 + src/base/QXmppGlobal.cpp | 34 + src/base/QXmppGlobal.h | 43 + src/base/QXmppIbbIq.cpp | 169 +++ src/base/QXmppIbbIq.h | 105 ++ src/base/QXmppIq.cpp | 147 ++ src/base/QXmppIq.h | 73 + src/base/QXmppJingleIq.cpp | 848 +++++++++++ src/base/QXmppJingleIq.h | 330 +++++ src/base/QXmppLogger.cpp | 245 ++++ src/base/QXmppLogger.h | 169 +++ src/base/QXmppMessage.cpp | 417 ++++++ src/base/QXmppMessage.h | 123 ++ src/base/QXmppMucIq.cpp | 300 ++++ src/base/QXmppMucIq.h | 152 ++ src/base/QXmppNonSASLAuth.cpp | 106 ++ src/base/QXmppNonSASLAuth.h | 61 + src/base/QXmppPacket.cpp | 34 + src/base/QXmppPacket.h | 48 + src/base/QXmppPingIq.cpp | 47 + src/base/QXmppPingIq.h | 40 + src/base/QXmppPresence.cpp | 510 +++++++ src/base/QXmppPresence.h | 176 +++ src/base/QXmppPubSubIq.cpp | 253 ++++ src/base/QXmppPubSubIq.h | 108 ++ src/base/QXmppRosterIq.cpp | 253 ++++ src/base/QXmppRosterIq.h | 107 ++ src/base/QXmppRpcIq.cpp | 443 ++++++ src/base/QXmppRpcIq.h | 130 ++ src/base/QXmppRtpChannel.cpp | 1042 ++++++++++++++ src/base/QXmppRtpChannel.h | 289 ++++ src/base/QXmppSaslAuth.cpp | 214 +++ src/base/QXmppSaslAuth.h | 72 + src/base/QXmppSessionIq.cpp | 44 + src/base/QXmppSessionIq.h | 49 + src/base/QXmppSocks.cpp | 345 +++++ src/base/QXmppSocks.h | 81 ++ src/base/QXmppStanza.cpp | 436 ++++++ src/base/QXmppStanza.h | 162 +++ src/base/QXmppStream.cpp | 259 ++++ src/base/QXmppStream.h | 92 ++ src/base/QXmppStreamFeatures.cpp | 222 +++ src/base/QXmppStreamFeatures.h | 76 + src/base/QXmppStreamInitiationIq.cpp | 106 ++ src/base/QXmppStreamInitiationIq.h | 69 + src/base/QXmppStun.cpp | 2581 ++++++++++++++++++++++++++++++++++ src/base/QXmppStun.h | 440 ++++++ src/base/QXmppUtils.cpp | 339 +++++ src/base/QXmppUtils.h | 66 + src/base/QXmppVCardIq.cpp | 310 ++++ src/base/QXmppVCardIq.h | 105 ++ src/base/QXmppVersionIq.cpp | 111 ++ src/base/QXmppVersionIq.h | 62 + src/base/qdnslookup.cpp | 989 +++++++++++++ src/base/qdnslookup.h | 238 ++++ src/base/qdnslookup_p.h | 216 +++ src/base/qdnslookup_stub.cpp | 54 + src/base/qdnslookup_symbian.cpp | 98 ++ src/base/qdnslookup_unix.cpp | 323 +++++ src/base/qdnslookup_win.cpp | 183 +++ src/qdnslookup.cpp | 989 ------------- src/qdnslookup.h | 238 ---- src/qdnslookup_p.h | 216 --- src/qdnslookup_stub.cpp | 54 - src/qdnslookup_symbian.cpp | 98 -- src/qdnslookup_unix.cpp | 323 ----- src/qdnslookup_win.cpp | 183 --- src/src.pro | 87 +- 159 files changed, 19757 insertions(+), 19842 deletions(-) delete mode 100644 src/QXmppArchiveIq.cpp delete mode 100644 src/QXmppArchiveIq.h delete mode 100644 src/QXmppBindIq.cpp delete mode 100644 src/QXmppBindIq.h delete mode 100644 src/QXmppBookmarkSet.cpp delete mode 100644 src/QXmppBookmarkSet.h delete mode 100644 src/QXmppByteStreamIq.cpp delete mode 100644 src/QXmppByteStreamIq.h delete mode 100644 src/QXmppCodec.cpp delete mode 100644 src/QXmppCodec.h delete mode 100644 src/QXmppConstants.cpp delete mode 100644 src/QXmppConstants.h delete mode 100644 src/QXmppDataForm.cpp delete mode 100644 src/QXmppDataForm.h delete mode 100644 src/QXmppDiscoveryIq.cpp delete mode 100644 src/QXmppDiscoveryIq.h delete mode 100644 src/QXmppElement.cpp delete mode 100644 src/QXmppElement.h delete mode 100644 src/QXmppEntityTimeIq.cpp delete mode 100644 src/QXmppEntityTimeIq.h delete mode 100644 src/QXmppGlobal.cpp delete mode 100644 src/QXmppGlobal.h delete mode 100644 src/QXmppIbbIq.cpp delete mode 100644 src/QXmppIbbIq.h delete mode 100644 src/QXmppIq.cpp delete mode 100644 src/QXmppIq.h delete mode 100644 src/QXmppJingleIq.cpp delete mode 100644 src/QXmppJingleIq.h delete mode 100644 src/QXmppLogger.cpp delete mode 100644 src/QXmppLogger.h delete mode 100644 src/QXmppMessage.cpp delete mode 100644 src/QXmppMessage.h delete mode 100644 src/QXmppMucIq.cpp delete mode 100644 src/QXmppMucIq.h delete mode 100644 src/QXmppNonSASLAuth.cpp delete mode 100644 src/QXmppNonSASLAuth.h delete mode 100644 src/QXmppPacket.cpp delete mode 100644 src/QXmppPacket.h delete mode 100644 src/QXmppPingIq.cpp delete mode 100644 src/QXmppPingIq.h delete mode 100644 src/QXmppPresence.cpp delete mode 100644 src/QXmppPresence.h delete mode 100644 src/QXmppPubSubIq.cpp delete mode 100644 src/QXmppPubSubIq.h delete mode 100644 src/QXmppRosterIq.cpp delete mode 100644 src/QXmppRosterIq.h delete mode 100644 src/QXmppRpcIq.cpp delete mode 100644 src/QXmppRpcIq.h delete mode 100644 src/QXmppRtpChannel.cpp delete mode 100644 src/QXmppRtpChannel.h delete mode 100644 src/QXmppSaslAuth.cpp delete mode 100644 src/QXmppSaslAuth.h delete mode 100644 src/QXmppSessionIq.cpp delete mode 100644 src/QXmppSessionIq.h delete mode 100644 src/QXmppSocks.cpp delete mode 100644 src/QXmppSocks.h delete mode 100644 src/QXmppStanza.cpp delete mode 100644 src/QXmppStanza.h delete mode 100644 src/QXmppStream.cpp delete mode 100644 src/QXmppStream.h delete mode 100644 src/QXmppStreamFeatures.cpp delete mode 100644 src/QXmppStreamFeatures.h delete mode 100644 src/QXmppStreamInitiationIq.cpp delete mode 100644 src/QXmppStreamInitiationIq.h delete mode 100644 src/QXmppStun.cpp delete mode 100644 src/QXmppStun.h delete mode 100644 src/QXmppUtils.cpp delete mode 100644 src/QXmppUtils.h delete mode 100644 src/QXmppVCardIq.cpp delete mode 100644 src/QXmppVCardIq.h delete mode 100644 src/QXmppVersionIq.cpp delete mode 100644 src/QXmppVersionIq.h create mode 100644 src/base/QXmppArchiveIq.cpp create mode 100644 src/base/QXmppArchiveIq.h create mode 100644 src/base/QXmppBindIq.cpp create mode 100644 src/base/QXmppBindIq.h create mode 100644 src/base/QXmppBookmarkSet.cpp create mode 100644 src/base/QXmppBookmarkSet.h create mode 100644 src/base/QXmppByteStreamIq.cpp create mode 100644 src/base/QXmppByteStreamIq.h create mode 100644 src/base/QXmppCodec.cpp create mode 100644 src/base/QXmppCodec.h create mode 100644 src/base/QXmppConstants.cpp create mode 100644 src/base/QXmppConstants.h create mode 100644 src/base/QXmppDataForm.cpp create mode 100644 src/base/QXmppDataForm.h create mode 100644 src/base/QXmppDiscoveryIq.cpp create mode 100644 src/base/QXmppDiscoveryIq.h create mode 100644 src/base/QXmppElement.cpp create mode 100644 src/base/QXmppElement.h create mode 100644 src/base/QXmppEntityTimeIq.cpp create mode 100644 src/base/QXmppEntityTimeIq.h create mode 100644 src/base/QXmppGlobal.cpp create mode 100644 src/base/QXmppGlobal.h create mode 100644 src/base/QXmppIbbIq.cpp create mode 100644 src/base/QXmppIbbIq.h create mode 100644 src/base/QXmppIq.cpp create mode 100644 src/base/QXmppIq.h create mode 100644 src/base/QXmppJingleIq.cpp create mode 100644 src/base/QXmppJingleIq.h create mode 100644 src/base/QXmppLogger.cpp create mode 100644 src/base/QXmppLogger.h create mode 100644 src/base/QXmppMessage.cpp create mode 100644 src/base/QXmppMessage.h create mode 100644 src/base/QXmppMucIq.cpp create mode 100644 src/base/QXmppMucIq.h create mode 100644 src/base/QXmppNonSASLAuth.cpp create mode 100644 src/base/QXmppNonSASLAuth.h create mode 100644 src/base/QXmppPacket.cpp create mode 100644 src/base/QXmppPacket.h create mode 100644 src/base/QXmppPingIq.cpp create mode 100644 src/base/QXmppPingIq.h create mode 100644 src/base/QXmppPresence.cpp create mode 100644 src/base/QXmppPresence.h create mode 100644 src/base/QXmppPubSubIq.cpp create mode 100644 src/base/QXmppPubSubIq.h create mode 100644 src/base/QXmppRosterIq.cpp create mode 100644 src/base/QXmppRosterIq.h create mode 100644 src/base/QXmppRpcIq.cpp create mode 100644 src/base/QXmppRpcIq.h create mode 100644 src/base/QXmppRtpChannel.cpp create mode 100644 src/base/QXmppRtpChannel.h create mode 100644 src/base/QXmppSaslAuth.cpp create mode 100644 src/base/QXmppSaslAuth.h create mode 100644 src/base/QXmppSessionIq.cpp create mode 100644 src/base/QXmppSessionIq.h create mode 100644 src/base/QXmppSocks.cpp create mode 100644 src/base/QXmppSocks.h create mode 100644 src/base/QXmppStanza.cpp create mode 100644 src/base/QXmppStanza.h create mode 100644 src/base/QXmppStream.cpp create mode 100644 src/base/QXmppStream.h create mode 100644 src/base/QXmppStreamFeatures.cpp create mode 100644 src/base/QXmppStreamFeatures.h create mode 100644 src/base/QXmppStreamInitiationIq.cpp create mode 100644 src/base/QXmppStreamInitiationIq.h create mode 100644 src/base/QXmppStun.cpp create mode 100644 src/base/QXmppStun.h create mode 100644 src/base/QXmppUtils.cpp create mode 100644 src/base/QXmppUtils.h create mode 100644 src/base/QXmppVCardIq.cpp create mode 100644 src/base/QXmppVCardIq.h create mode 100644 src/base/QXmppVersionIq.cpp create mode 100644 src/base/QXmppVersionIq.h create mode 100644 src/base/qdnslookup.cpp create mode 100644 src/base/qdnslookup.h create mode 100644 src/base/qdnslookup_p.h create mode 100644 src/base/qdnslookup_stub.cpp create mode 100644 src/base/qdnslookup_symbian.cpp create mode 100644 src/base/qdnslookup_unix.cpp create mode 100644 src/base/qdnslookup_win.cpp delete mode 100644 src/qdnslookup.cpp delete mode 100644 src/qdnslookup.h delete mode 100644 src/qdnslookup_p.h delete mode 100644 src/qdnslookup_stub.cpp delete mode 100644 src/qdnslookup_symbian.cpp delete mode 100644 src/qdnslookup_unix.cpp delete mode 100644 src/qdnslookup_win.cpp (limited to 'src') diff --git a/src/QXmppArchiveIq.cpp b/src/QXmppArchiveIq.cpp deleted file mode 100644 index e8bef8fc..00000000 --- a/src/QXmppArchiveIq.cpp +++ /dev/null @@ -1,572 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include "QXmppArchiveIq.h" -#include "QXmppUtils.h" - -static const char *ns_archive = "urn:xmpp:archive"; -static const char *ns_rsm = "http://jabber.org/protocol/rsm"; - -QXmppArchiveMessage::QXmppArchiveMessage() - : m_received(false) -{ -} - -/// Returns the archived message's body. - -QString QXmppArchiveMessage::body() const -{ - return m_body; -} - -/// Sets the archived message's body. -/// -/// \param body -void QXmppArchiveMessage::setBody(const QString &body) -{ - m_body = body; -} - -/// Returns the archived message's date. - -QDateTime QXmppArchiveMessage::date() const -{ - return m_date; -} - -//// Sets the archived message's date. -/// -/// \param date - -void QXmppArchiveMessage::setDate(const QDateTime &date) -{ - m_date = date; -} - -/// Returns true if the archived message was received, false if it was sent. - -bool QXmppArchiveMessage::isReceived() const -{ - return m_received; -} - -/// Set to true if the archived message was received, false if it was sent. -/// -/// \param isReceived - -void QXmppArchiveMessage::setReceived(bool isReceived) -{ - m_received = isReceived; -} - -QXmppArchiveChat::QXmppArchiveChat() - : m_version(0) -{ -} - -void QXmppArchiveChat::parse(const QDomElement &element) -{ - m_with = element.attribute("with"); - m_start = datetimeFromString(element.attribute("start")); - m_subject = element.attribute("subject"); - m_thread = element.attribute("thread"); - m_version = element.attribute("version").toInt(); - - QDomElement child = element.firstChildElement(); - while (!child.isNull()) - { - if ((child.tagName() == "from") || (child.tagName() == "to")) - { - QXmppArchiveMessage message; - message.setBody(child.firstChildElement("body").text()); - message.setDate(m_start.addSecs(child.attribute("secs").toInt())); - message.setReceived(child.tagName() == "from"); - m_messages << message; - } - child = child.nextSiblingElement(); - } -} - -void QXmppArchiveChat::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("chat"); - writer->writeAttribute("xmlns", ns_archive); - helperToXmlAddAttribute(writer, "with", m_with); - if (m_start.isValid()) - helperToXmlAddAttribute(writer, "start", datetimeToString(m_start)); - helperToXmlAddAttribute(writer, "subject", m_subject); - helperToXmlAddAttribute(writer, "thread", m_thread); - if (m_version) - helperToXmlAddAttribute(writer, "version", QString::number(m_version)); - foreach (const QXmppArchiveMessage &message, m_messages) - { - writer->writeStartElement(message.isReceived() ? "from" : "to"); - helperToXmlAddAttribute(writer, "secs", QString::number(m_start.secsTo(message.date()))); - writer->writeTextElement("body", message.body()); - writer->writeEndElement(); - } - writer->writeEndElement(); -} - -/// Returns the conversation's messages. - -QList QXmppArchiveChat::messages() const -{ - return m_messages; -} - -/// Sets the conversation's messages. - -void QXmppArchiveChat::setMessages(const QList &messages) -{ - m_messages = messages; -} - -/// Returns the start of this conversation. - -QDateTime QXmppArchiveChat::start() const -{ - return m_start; -} - -/// Sets the start of this conversation. - -void QXmppArchiveChat::setStart(const QDateTime &start) -{ - m_start = start; -} - -/// Returns the conversation's subject. - -QString QXmppArchiveChat::subject() const -{ - return m_subject; -} - -/// Sets the conversation's subject. - -void QXmppArchiveChat::setSubject(const QString &subject) -{ - m_subject = subject; -} - -/// Returns the conversation's thread. - -QString QXmppArchiveChat::thread() const -{ - return m_thread; -} - -/// Sets the conversation's thread. - -void QXmppArchiveChat::setThread(const QString &thread) -{ - m_thread = thread; -} - -/// Returns the conversation's version. - -int QXmppArchiveChat::version() const -{ - return m_version; -} - -/// Sets the conversation's version. - -void QXmppArchiveChat::setVersion(int version) -{ - m_version = version; -} - -/// Returns the JID of the remote party. - -QString QXmppArchiveChat::with() const -{ - return m_with; -} - -/// Sets the JID of the remote party. - -void QXmppArchiveChat::setWith(const QString &with) -{ - m_with = with; -} - -/// Returns the chat conversation carried by this IQ. - -QXmppArchiveChat QXmppArchiveChatIq::chat() const -{ - return m_chat; -} - -/// Sets the chat conversation carried by this IQ. - -void QXmppArchiveChatIq::setChat(const QXmppArchiveChat &chat) -{ - m_chat = chat; -} - -bool QXmppArchiveChatIq::isArchiveChatIq(const QDomElement &element) -{ - QDomElement chatElement = element.firstChildElement("chat"); - return !chatElement.attribute("with").isEmpty(); - //return (chatElement.namespaceURI() == ns_archive); -} - -void QXmppArchiveChatIq::parseElementFromChild(const QDomElement &element) -{ - m_chat.parse(element.firstChildElement("chat")); -} - -void QXmppArchiveChatIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - m_chat.toXml(writer); -} - -/// Constructs a QXmppArchiveListIq. - -QXmppArchiveListIq::QXmppArchiveListIq() - : QXmppIq(QXmppIq::Get), m_max(0) -{ -} - -/// Returns the list of chat conversations. - -QList QXmppArchiveListIq::chats() const -{ - return m_chats; -} - -/// Sets the list of chat conversations. - -void QXmppArchiveListIq::setChats(const QList &chats) -{ - m_chats = chats; -} - -/// Returns the maximum number of results. -/// - -int QXmppArchiveListIq::max() const -{ - return m_max; -} - -/// Sets the maximum number of results. -/// -/// \param max - -void QXmppArchiveListIq::setMax(int max) -{ - m_max = max; -} - -/// Returns the JID which archived conversations must match. -/// - -QString QXmppArchiveListIq::with() const -{ - return m_with; -} - -/// Sets the JID which archived conversations must match. -/// -/// \param with - -void QXmppArchiveListIq::setWith(const QString &with) -{ - m_with = with; -} - -/// Returns the start date/time for the archived conversations. -/// - -QDateTime QXmppArchiveListIq::start() const -{ - return m_start; -} - -/// Sets the start date/time for the archived conversations. -/// -/// \param start - -void QXmppArchiveListIq::setStart(const QDateTime &start) -{ - m_start = start; -} - -/// Returns the end date/time for the archived conversations. -/// - -QDateTime QXmppArchiveListIq::end() const -{ - return m_end; -} - -/// Sets the end date/time for the archived conversations. -/// -/// \param end - -void QXmppArchiveListIq::setEnd(const QDateTime &end) -{ - m_end = end; -} - -bool QXmppArchiveListIq::isArchiveListIq(const QDomElement &element) -{ - QDomElement listElement = element.firstChildElement("list"); - return (listElement.namespaceURI() == ns_archive); -} - -void QXmppArchiveListIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement listElement = element.firstChildElement("list"); - m_with = listElement.attribute("with"); - m_start = datetimeFromString(listElement.attribute("start")); - m_end = datetimeFromString(listElement.attribute("end")); - - QDomElement setElement = listElement.firstChildElement("set"); - if (setElement.namespaceURI() == ns_rsm) - m_max = setElement.firstChildElement("max").text().toInt(); - - QDomElement child = listElement.firstChildElement(); - while (!child.isNull()) - { - if (child.tagName() == "chat") - { - QXmppArchiveChat chat; - chat.parse(child); - m_chats << chat; - } - child = child.nextSiblingElement(); - } -} - -void QXmppArchiveListIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("list"); - writer->writeAttribute("xmlns", ns_archive); - if (!m_with.isEmpty()) - helperToXmlAddAttribute(writer, "with", m_with); - if (m_start.isValid()) - helperToXmlAddAttribute(writer, "start", datetimeToString(m_start)); - if (m_end.isValid()) - helperToXmlAddAttribute(writer, "end", datetimeToString(m_end)); - if (m_max > 0) - { - writer->writeStartElement("set"); - writer->writeAttribute("xmlns", ns_rsm); - helperToXmlAddTextElement(writer, "max", QString::number(m_max)); - writer->writeEndElement(); - } - foreach (const QXmppArchiveChat &chat, m_chats) - chat.toXml(writer); - writer->writeEndElement(); -} - -bool QXmppArchivePrefIq::isArchivePrefIq(const QDomElement &element) -{ - QDomElement prefElement = element.firstChildElement("pref"); - return (prefElement.namespaceURI() == ns_archive); -} - -void QXmppArchivePrefIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("pref"); - Q_UNUSED(queryElement); -} - -void QXmppArchivePrefIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("pref"); - writer->writeAttribute("xmlns", ns_archive); - writer->writeEndElement(); -} - -/// Returns the JID which archived conversations must match. -/// - -QString QXmppArchiveRemoveIq::with() const -{ - return m_with; -} - -/// Sets the JID which archived conversations must match. -/// -/// \param with - -void QXmppArchiveRemoveIq::setWith(const QString &with) -{ - m_with = with; -} - -/// Returns the start date/time for the archived conversations. -/// - -QDateTime QXmppArchiveRemoveIq::start() const -{ - return m_start; -} - -/// Sets the start date/time for the archived conversations. -/// -/// \param start - -void QXmppArchiveRemoveIq::setStart(const QDateTime &start) -{ - m_start = start; -} - -/// Returns the end date/time for the archived conversations. -/// - -QDateTime QXmppArchiveRemoveIq::end() const -{ - return m_end; -} - -/// Sets the end date/time for the archived conversations. -/// -/// \param end - -void QXmppArchiveRemoveIq::setEnd(const QDateTime &end) -{ - m_end = end; -} - -bool QXmppArchiveRemoveIq::isArchiveRemoveIq(const QDomElement &element) -{ - QDomElement retrieveElement = element.firstChildElement("remove"); - return (retrieveElement.namespaceURI() == ns_archive); -} - -void QXmppArchiveRemoveIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement listElement = element.firstChildElement("remove"); - m_with = listElement.attribute("with"); - m_start = datetimeFromString(listElement.attribute("start")); - m_end = datetimeFromString(listElement.attribute("end")); -} - -void QXmppArchiveRemoveIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("remove"); - writer->writeAttribute("xmlns", ns_archive); - if (!m_with.isEmpty()) - helperToXmlAddAttribute(writer, "with", m_with); - if (m_start.isValid()) - helperToXmlAddAttribute(writer, "start", datetimeToString(m_start)); - if (m_end.isValid()) - helperToXmlAddAttribute(writer, "end", datetimeToString(m_end)); - writer->writeEndElement(); -} - -QXmppArchiveRetrieveIq::QXmppArchiveRetrieveIq() - : QXmppIq(QXmppIq::Get), m_max(0) -{ -} - -/// Returns the maximum number of results. -/// - -int QXmppArchiveRetrieveIq::max() const -{ - return m_max; -} - -/// Sets the maximum number of results. -/// -/// \param max - -void QXmppArchiveRetrieveIq::setMax(int max) -{ - m_max = max; -} - -/// Returns the start date/time for the archived conversations. -/// - -QDateTime QXmppArchiveRetrieveIq::start() const -{ - return m_start; -} - -/// Sets the start date/time for the archived conversations. -/// -/// \param start - -void QXmppArchiveRetrieveIq::setStart(const QDateTime &start) -{ - m_start = start; -} - -/// Returns the JID which archived conversations must match. -/// - -QString QXmppArchiveRetrieveIq::with() const -{ - return m_with; -} - -/// Sets the JID which archived conversations must match. -/// -/// \param with - -void QXmppArchiveRetrieveIq::setWith(const QString &with) -{ - m_with = with; -} - -bool QXmppArchiveRetrieveIq::isArchiveRetrieveIq(const QDomElement &element) -{ - QDomElement retrieveElement = element.firstChildElement("retrieve"); - return (retrieveElement.namespaceURI() == ns_archive); -} - -void QXmppArchiveRetrieveIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement retrieveElement = element.firstChildElement("retrieve"); - m_with = retrieveElement.attribute("with"); - m_start = datetimeFromString(retrieveElement.attribute("start")); - QDomElement setElement = retrieveElement.firstChildElement("set"); - if (setElement.namespaceURI() == ns_rsm) - m_max = setElement.firstChildElement("max").text().toInt(); -} - -void QXmppArchiveRetrieveIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("retrieve"); - writer->writeAttribute("xmlns", ns_archive); - helperToXmlAddAttribute(writer, "with", m_with); - helperToXmlAddAttribute(writer, "start", datetimeToString(m_start)); - if (m_max > 0) - { - writer->writeStartElement("set"); - writer->writeAttribute("xmlns", ns_rsm); - helperToXmlAddTextElement(writer, "max", QString::number(m_max)); - writer->writeEndElement(); - } - writer->writeEndElement(); -} diff --git a/src/QXmppArchiveIq.h b/src/QXmppArchiveIq.h deleted file mode 100644 index c0784891..00000000 --- a/src/QXmppArchiveIq.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPARCHIVEIQ_H -#define QXMPPARCHIVEIQ_H - -#include "QXmppIq.h" - -#include - -class QXmlStreamWriter; -class QDomElement; - -/// \brief The QXmppArchiveMessage represents an archived message -/// as defined by XEP-0136: Message Archiving. - -class QXmppArchiveMessage -{ -public: - QXmppArchiveMessage(); - - QString body() const; - void setBody(const QString &body); - - QDateTime date() const; - void setDate(const QDateTime &date); - - bool isReceived() const; - void setReceived(bool isReceived); - -private: - QString m_body; - QDateTime m_date; - bool m_received; -}; - -/// \brief The QXmppArchiveChat represents an archived conversation -/// as defined by XEP-0136: Message Archiving. - -class QXmppArchiveChat -{ -public: - QXmppArchiveChat(); - - QList messages() const; - void setMessages(const QList &messages); - - QDateTime start() const; - void setStart(const QDateTime &start); - - QString subject() const; - void setSubject(const QString &subject); - - QString thread() const; - void setThread(const QString &thread); - - int version() const; - void setVersion(int version); - - QString with() const; - void setWith(const QString &with); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QList m_messages; - QDateTime m_start; - QString m_subject; - QString m_thread; - int m_version; - QString m_with; -}; - -/// \brief Represents an archive chat as defined by XEP-0136: Message Archiving. -/// -/// It is used to get chat as a QXmppArchiveChat. -/// -/// \ingroup Stanzas - -class QXmppArchiveChatIq : public QXmppIq -{ -public: - QXmppArchiveChat chat() const; - void setChat(const QXmppArchiveChat &chat); - - /// \cond - static bool isArchiveChatIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QXmppArchiveChat m_chat; -}; - -/// \brief Represents an archive list as defined by XEP-0136: Message Archiving. -/// -/// \ingroup Stanzas - -class QXmppArchiveListIq : public QXmppIq -{ -public: - QXmppArchiveListIq(); - - QList chats() const; - void setChats(const QList &chats); - - int max() const; - void setMax(int max); - - QString with() const; - void setWith( const QString &with ); - - QDateTime start() const; - void setStart(const QDateTime &start ); - - QDateTime end() const; - void setEnd(const QDateTime &end ); - - /// \cond - static bool isArchiveListIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - int m_max; - QString m_with; - QDateTime m_start; - QDateTime m_end; - QList m_chats; -}; - -/// \brief Represents an archive remove IQ as defined by XEP-0136: Message Archiving. -/// -/// \ingroup Stanzas - -class QXmppArchiveRemoveIq : public QXmppIq -{ -public: - QString with() const; - void setWith( const QString &with ); - - QDateTime start() const; - void setStart(const QDateTime &start ); - - QDateTime end() const; - void setEnd(const QDateTime &end ); - - /// \cond - static bool isArchiveRemoveIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString m_with; - QDateTime m_start; - QDateTime m_end; -}; - -/// \brief Represents an archive retrieve IQ as defined by XEP-0136: Message Archiving. -/// -/// \ingroup Stanzas - -class QXmppArchiveRetrieveIq : public QXmppIq -{ -public: - QXmppArchiveRetrieveIq(); - - int max() const; - void setMax(int max); - - QDateTime start() const; - void setStart(const QDateTime &start); - - QString with() const; - void setWith(const QString &with); - - /// \cond - static bool isArchiveRetrieveIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - int m_max; - QString m_with; - QDateTime m_start; -}; - -/// \brief Represents an archive preference IQ as defined by XEP-0136: Message Archiving. -/// -/// \ingroup Stanzas - -class QXmppArchivePrefIq : public QXmppIq -{ -public: - /// \cond - static bool isArchivePrefIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond -}; - -#endif // QXMPPARCHIVEIQ_H diff --git a/src/QXmppBindIq.cpp b/src/QXmppBindIq.cpp deleted file mode 100644 index f818e002..00000000 --- a/src/QXmppBindIq.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include -#include -#include - -#include "QXmppBindIq.h" -#include "QXmppUtils.h" -#include "QXmppConstants.h" - -/// Returns the bound JID. -/// - -QString QXmppBindIq::jid() const -{ - return m_jid; -} - -/// Sets the bound JID. -/// -/// \param jid - -void QXmppBindIq::setJid(const QString& jid) -{ - m_jid = jid; -} - -/// Returns the requested resource. -/// - -QString QXmppBindIq::resource() const -{ - return m_resource; -} - -/// Sets the requested resource. -/// -/// \param resource - -void QXmppBindIq::setResource(const QString& resource) -{ - m_resource = resource; -} - -bool QXmppBindIq::isBindIq(const QDomElement &element) -{ - QDomElement bindElement = element.firstChildElement("bind"); - return (bindElement.namespaceURI() == ns_bind); -} - -void QXmppBindIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement bindElement = element.firstChildElement("bind"); - m_jid = bindElement.firstChildElement("jid").text(); - m_resource = bindElement.firstChildElement("resource").text(); -} - -void QXmppBindIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("bind"); - writer->writeAttribute("xmlns", ns_bind); - if (!m_jid.isEmpty()) - helperToXmlAddTextElement(writer, "jid", m_jid); - if (!m_resource.isEmpty()) - helperToXmlAddTextElement(writer, "resource", m_resource); - writer->writeEndElement(); -} - diff --git a/src/QXmppBindIq.h b/src/QXmppBindIq.h deleted file mode 100644 index 0131510c..00000000 --- a/src/QXmppBindIq.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPBINDIQ_H -#define QXMPPBINDIQ_H - -#include "QXmppIq.h" - -/// \brief The QXmppBindIq class represents an IQ used for resource -/// binding as defined by RFC 5921. -/// -/// \ingroup Stanzas - -class QXmppBindIq : public QXmppIq -{ -public: - QString jid() const; - void setJid(const QString&); - - QString resource() const; - void setResource(const QString&); - - /// \cond - static bool isBindIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString m_jid; - QString m_resource; -}; - -#endif // QXMPPBIND_H diff --git a/src/QXmppBookmarkSet.cpp b/src/QXmppBookmarkSet.cpp deleted file mode 100644 index b418d498..00000000 --- a/src/QXmppBookmarkSet.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include "QXmppBookmarkSet.h" -#include "QXmppUtils.h" - -static const char *ns_bookmarks = "storage:bookmarks"; - -/// Constructs a new conference room bookmark. -/// - -QXmppBookmarkConference::QXmppBookmarkConference() - : m_autoJoin(false) -{ -} - -/// Returns whether the client should automatically join the conference room -/// on login. -/// - -bool QXmppBookmarkConference::autoJoin() const -{ - return m_autoJoin; -} - -/// Sets whether the client should automatically join the conference room -/// on login. -/// -/// \param autoJoin - -void QXmppBookmarkConference::setAutoJoin(bool autoJoin) -{ - m_autoJoin = autoJoin; -} - -/// Returns the JID of the conference room. -/// - -QString QXmppBookmarkConference::jid() const -{ - return m_jid; -} - -/// Sets the JID of the conference room. -/// -/// \param jid - -void QXmppBookmarkConference::setJid(const QString &jid) -{ - m_jid = jid; -} - -/// Returns the friendly name for the bookmark. -/// - -QString QXmppBookmarkConference::name() const -{ - return m_name; -} - -/// Sets the friendly name for the bookmark. -/// -/// \param name - -void QXmppBookmarkConference::setName(const QString &name) -{ - m_name = name; -} - -/// Returns the preferred nickname for the conference room. -/// - -QString QXmppBookmarkConference::nickName() const -{ - return m_nickName; -} - -/// Sets the preferred nickname for the conference room. -/// -/// \param nickName - -void QXmppBookmarkConference::setNickName(const QString &nickName) -{ - m_nickName = nickName; -} - -/// Returns the friendly name for the bookmark. -/// - -QString QXmppBookmarkUrl::name() const -{ - return m_name; -} - -/// Sets the friendly name for the bookmark. -/// -/// \param name - -void QXmppBookmarkUrl::setName(const QString &name) -{ - m_name = name; -} - -/// Returns the URL for the web page. -/// - -QUrl QXmppBookmarkUrl::url() const -{ - return m_url; -} - -/// Sets the URL for the web page. -/// -/// \param url - -void QXmppBookmarkUrl::setUrl(const QUrl &url) -{ - m_url = url; -} - -/// Returns the conference rooms bookmarks in this bookmark set. -/// - -QList QXmppBookmarkSet::conferences() const -{ - return m_conferences; -} - -/// Sets the conference rooms bookmarks in this bookmark set. -/// -/// \param conferences - -void QXmppBookmarkSet::setConferences(const QList &conferences) -{ - m_conferences = conferences; -} - -/// Returns the web page bookmarks in this bookmark set. -/// - -QList QXmppBookmarkSet::urls() const -{ - return m_urls; -} - -/// Sets the web page bookmarks in this bookmark set. -/// -/// \param urls - -void QXmppBookmarkSet::setUrls(const QList &urls) -{ - m_urls = urls; -} - -bool QXmppBookmarkSet::isBookmarkSet(const QDomElement &element) -{ - return element.tagName() == "storage" && - element.namespaceURI() == ns_bookmarks; -} - -void QXmppBookmarkSet::parse(const QDomElement &element) -{ - QDomElement childElement = element.firstChildElement(); - while (!childElement.isNull()) - { - if (childElement.tagName() == "conference") - { - QXmppBookmarkConference conference; - conference.setAutoJoin(childElement.attribute("autojoin") == "true"); - conference.setJid(childElement.attribute("jid")); - conference.setName(childElement.attribute("name")); - conference.setNickName(childElement.firstChildElement("nick").text()); - m_conferences << conference; - } - else if (childElement.tagName() == "url") - { - QXmppBookmarkUrl url; - url.setName(childElement.attribute("name")); - url.setUrl(childElement.attribute("url")); - m_urls << url; - } - childElement = childElement.nextSiblingElement(); - } -} - -void QXmppBookmarkSet::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("storage"); - writer->writeAttribute("xmlns", ns_bookmarks); - foreach (const QXmppBookmarkConference &conference, m_conferences) - { - writer->writeStartElement("conference"); - if (conference.autoJoin()) - helperToXmlAddAttribute(writer, "autojoin", "true"); - helperToXmlAddAttribute(writer, "jid", conference.jid()); - helperToXmlAddAttribute(writer, "name", conference.name()); - if (!conference.nickName().isEmpty()) - helperToXmlAddTextElement(writer, "nick", conference.nickName()); - writer->writeEndElement(); - } - foreach (const QXmppBookmarkUrl &url, m_urls) - { - writer->writeStartElement("url"); - helperToXmlAddAttribute(writer, "name", url.name()); - helperToXmlAddAttribute(writer, "url", url.url().toString()); - writer->writeEndElement(); - } - writer->writeEndElement(); -} - diff --git a/src/QXmppBookmarkSet.h b/src/QXmppBookmarkSet.h deleted file mode 100644 index aa90f2cf..00000000 --- a/src/QXmppBookmarkSet.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPBOOKMARKSET_H -#define QXMPPBOOKMARKSET_H - -#include -#include -#include -#include - -class QDomElement; - -/// \brief The QXmppBookmarkConference class represents a bookmark for a conference room, -/// as defined by XEP-0048: Bookmarks. -/// -class QXmppBookmarkConference -{ -public: - QXmppBookmarkConference(); - - bool autoJoin() const; - void setAutoJoin(bool autoJoin); - - QString jid() const; - void setJid(const QString &jid); - - QString name() const; - void setName(const QString &name); - - QString nickName() const; - void setNickName(const QString &nickName); - -private: - bool m_autoJoin; - QString m_jid; - QString m_name; - QString m_nickName; -}; - -/// \brief The QXmppBookmarkUrl class represents a bookmark for a web page, -/// as defined by XEP-0048: Bookmarks. -/// -class QXmppBookmarkUrl -{ -public: - QString name() const; - void setName(const QString &name); - - QUrl url() const; - void setUrl(const QUrl &url); - -private: - QString m_name; - QUrl m_url; -}; - -/// \brief The QXmppbookmarkSets class represents a set of bookmarks, as defined -/// by XEP-0048: Bookmarks. -/// -class QXmppBookmarkSet -{ -public: - QList conferences() const; - void setConferences(const QList &conferences); - - QList urls() const; - void setUrls(const QList &urls); - - /// \cond - static bool isBookmarkSet(const QDomElement &element); - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endconf - -private: - QList m_conferences; - QList m_urls; -}; - -#endif diff --git a/src/QXmppByteStreamIq.cpp b/src/QXmppByteStreamIq.cpp deleted file mode 100644 index e1628e72..00000000 --- a/src/QXmppByteStreamIq.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include "QXmppByteStreamIq.h" -#include "QXmppConstants.h" -#include "QXmppUtils.h" - -QHostAddress QXmppByteStreamIq::StreamHost::host() const -{ - return m_host; -} - -void QXmppByteStreamIq::StreamHost::setHost(const QHostAddress &host) -{ - m_host = host; -} - -QString QXmppByteStreamIq::StreamHost::jid() const -{ - return m_jid; -} - -void QXmppByteStreamIq::StreamHost::setJid(const QString &jid) -{ - m_jid = jid; -} - -quint16 QXmppByteStreamIq::StreamHost::port() const -{ - return m_port; -} - -void QXmppByteStreamIq::StreamHost::setPort(quint16 port) -{ - m_port = port; -} - -QString QXmppByteStreamIq::StreamHost::zeroconf() const -{ - return m_zeroconf; -} - -void QXmppByteStreamIq::StreamHost::setZeroconf(const QString &zeroconf) -{ - m_zeroconf = zeroconf; -} - -QXmppByteStreamIq::Mode QXmppByteStreamIq::mode() const -{ - return m_mode; -} - -void QXmppByteStreamIq::setMode(QXmppByteStreamIq::Mode mode) -{ - m_mode = mode; -} - -QString QXmppByteStreamIq::sid() const -{ - return m_sid; -} - -void QXmppByteStreamIq::setSid(const QString &sid) -{ - m_sid = sid; -} - -QString QXmppByteStreamIq::activate() const -{ - return m_activate; -} - -void QXmppByteStreamIq::setActivate(const QString &activate) -{ - m_activate = activate; -} - -QList QXmppByteStreamIq::streamHosts() const -{ - return m_streamHosts; -} - -void QXmppByteStreamIq::setStreamHosts(const QList &streamHosts) -{ - m_streamHosts = streamHosts; -} - -QString QXmppByteStreamIq::streamHostUsed() const -{ - return m_streamHostUsed; -} - -void QXmppByteStreamIq::setStreamHostUsed(const QString &jid) -{ - m_streamHostUsed = jid; -} - -bool QXmppByteStreamIq::isByteStreamIq(const QDomElement &element) -{ - return element.firstChildElement("query").namespaceURI() == ns_bytestreams; -} - -void QXmppByteStreamIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - m_sid = queryElement.attribute("sid"); - const QString modeStr = queryElement.attribute("mode"); - if (modeStr == "tcp") - m_mode = Tcp; - else if (modeStr == "udp") - m_mode = Udp; - else - m_mode = None; - - QDomElement hostElement = queryElement.firstChildElement("streamhost"); - while (!hostElement.isNull()) - { - StreamHost streamHost; - streamHost.setHost(QHostAddress(hostElement.attribute("host"))); - streamHost.setJid(hostElement.attribute("jid")); - streamHost.setPort(hostElement.attribute("port").toInt()); - streamHost.setZeroconf(hostElement.attribute("zeroconf")); - m_streamHosts.append(streamHost); - - hostElement = hostElement.nextSiblingElement("streamhost"); - } - m_activate = queryElement.firstChildElement("activate").text(); - m_streamHostUsed = queryElement.firstChildElement("streamhost-used").attribute("jid"); -} - -void QXmppByteStreamIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("query"); - writer->writeAttribute("xmlns", ns_bytestreams); - helperToXmlAddAttribute(writer, "sid", m_sid); - QString modeStr; - if (m_mode == Tcp) - modeStr = "tcp"; - else if (m_mode == Udp) - modeStr = "udp"; - helperToXmlAddAttribute(writer, "mode", modeStr); - foreach (const StreamHost& streamHost, m_streamHosts) - { - writer->writeStartElement("streamhost"); - helperToXmlAddAttribute(writer, "host", streamHost.host().toString()); - helperToXmlAddAttribute(writer, "jid", streamHost.jid()); - helperToXmlAddAttribute(writer, "port", QString::number(streamHost.port())); - helperToXmlAddAttribute(writer, "zeroconf", streamHost.zeroconf()); - writer->writeEndElement(); - } - if (!m_activate.isEmpty()) - helperToXmlAddTextElement(writer, "activate", m_activate); - if (!m_streamHostUsed.isEmpty()) - { - writer->writeStartElement("streamhost-used"); - helperToXmlAddAttribute(writer, "jid", m_streamHostUsed); - writer->writeEndElement(); - } - - writer->writeEndElement(); -} diff --git a/src/QXmppByteStreamIq.h b/src/QXmppByteStreamIq.h deleted file mode 100644 index 604c12e5..00000000 --- a/src/QXmppByteStreamIq.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPBYTESTREAMIQ_H -#define QXMPPBYTESTREAMIQ_H - -#include "QXmppIq.h" - -#include - -class QDomElement; -class QXmlStreamWriter; - -class QXmppByteStreamIq : public QXmppIq -{ -public: - enum Mode { - None = 0, - Tcp, - Udp, - }; - - class StreamHost - { - public: - QString jid() const; - void setJid(const QString &jid); - - QHostAddress host() const; - void setHost(const QHostAddress &host); - - quint16 port() const; - void setPort(quint16 port); - - QString zeroconf() const; - void setZeroconf(const QString &zeroconf); - - private: - QHostAddress m_host; - QString m_jid; - quint16 m_port; - QString m_zeroconf; - }; - - QXmppByteStreamIq::Mode mode() const; - void setMode(QXmppByteStreamIq::Mode mode); - - QString sid() const; - void setSid(const QString &sid); - - QString activate() const; - void setActivate(const QString &activate); - - QList streamHosts() const; - void setStreamHosts(const QList &streamHosts); - - QString streamHostUsed() const; - void setStreamHostUsed(const QString &jid); - - static bool isByteStreamIq(const QDomElement &element); - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - Mode m_mode; - QString m_sid; - - QString m_activate; - QList m_streamHosts; - QString m_streamHostUsed; -}; - -#endif diff --git a/src/QXmppCodec.cpp b/src/QXmppCodec.cpp deleted file mode 100644 index a614ce01..00000000 --- a/src/QXmppCodec.cpp +++ /dev/null @@ -1,1218 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -/* - * G.711 based on reference implementation by Sun Microsystems, Inc. - */ - -#include -#include -#include - -#include "QXmppCodec.h" -#include "QXmppRtpChannel.h" - -#include - -#ifdef QXMPP_USE_SPEEX -#include -#endif - -#ifdef QXMPP_USE_THEORA -#include -#include -#endif - -#ifdef QXMPP_USE_VPX -#define VPX_CODEC_DISABLE_COMPAT 1 -#include -#include -#include -#include -#endif - -#define BIAS (0x84) /* Bias for linear code. */ -#define CLIP 8159 - -#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ -#define QUANT_MASK (0xf) /* Quantization field mask. */ -#define NSEGS (8) /* Number of A-law segments. */ -#define SEG_SHIFT (4) /* Left shift for segment number. */ -#define SEG_MASK (0x70) /* Segment field mask. */ - -enum FragmentType { - NoFragment = 0, - StartFragment, - MiddleFragment, - EndFragment, -}; - -static qint16 seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF, - 0x1FF, 0x3FF, 0x7FF, 0xFFF}; -static qint16 seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF, - 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; - -static qint16 search(qint16 val, qint16 *table, qint16 size) -{ - qint16 i; - - for (i = 0; i < size; i++) { - if (val <= *table++) - return (i); - } - return (size); -} - -/* - * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law - * - * Accepts a 16-bit integer and encodes it as A-law data. - * - * Linear Input Code Compressed Code - * ------------------------ --------------- - * 0000000wxyza 000wxyz - * 0000001wxyza 001wxyz - * 000001wxyzab 010wxyz - * 00001wxyzabc 011wxyz - * 0001wxyzabcd 100wxyz - * 001wxyzabcde 101wxyz - * 01wxyzabcdef 110wxyz - * 1wxyzabcdefg 111wxyz - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ -quint8 linear2alaw(qint16 pcm_val) -{ - qint16 mask; - qint16 seg; - quint8 aval; - - pcm_val = pcm_val >> 3; - - if (pcm_val >= 0) { - mask = 0xD5; /* sign (7th) bit = 1 */ - } else { - mask = 0x55; /* sign bit = 0 */ - pcm_val = -pcm_val - 1; - } - - /* Convert the scaled magnitude to segment number. */ - seg = search(pcm_val, seg_aend, 8); - - /* Combine the sign, segment, and quantization bits. */ - - if (seg >= 8) /* out of range, return maximum value. */ - return (quint8) (0x7F ^ mask); - else { - aval = (quint8) seg << SEG_SHIFT; - if (seg < 2) - aval |= (pcm_val >> 1) & QUANT_MASK; - else - aval |= (pcm_val >> seg) & QUANT_MASK; - return (aval ^ mask); - } -} - -/* - * alaw2linear() - Convert an A-law value to 16-bit linear PCM - * - */ -qint16 alaw2linear(quint8 a_val) -{ - qint16 t; - qint16 seg; - - a_val ^= 0x55; - - t = (a_val & QUANT_MASK) << 4; - seg = ((qint16)a_val & SEG_MASK) >> SEG_SHIFT; - switch (seg) { - case 0: - t += 8; - break; - case 1: - t += 0x108; - break; - default: - t += 0x108; - t <<= seg - 1; - } - return ((a_val & SIGN_BIT) ? t : -t); -} - -/* - * linear2ulaw() - Convert a linear PCM value to u-law - * - * In order to simplify the encoding process, the original linear magnitude - * is biased by adding 33 which shifts the encoding range from (0 - 8158) to - * (33 - 8191). The result can be seen in the following encoding table: - * - * Biased Linear Input Code Compressed Code - * ------------------------ --------------- - * 00000001wxyza 000wxyz - * 0000001wxyzab 001wxyz - * 000001wxyzabc 010wxyz - * 00001wxyzabcd 011wxyz - * 0001wxyzabcde 100wxyz - * 001wxyzabcdef 101wxyz - * 01wxyzabcdefg 110wxyz - * 1wxyzabcdefgh 111wxyz - * - * Each biased linear code has a leading 1 which identifies the segment - * number. The value of the segment number is equal to 7 minus the number - * of leading 0's. The quantization interval is directly available as the - * four bits wxyz. * The trailing bits (a - h) are ignored. - * - * Ordinarily the complement of the resulting code word is used for - * transmission, and so the code word is complemented before it is returned. - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ -quint8 linear2ulaw(qint16 pcm_val) -{ - qint16 mask; - qint16 seg; - quint8 uval; - - /* Get the sign and the magnitude of the value. */ - pcm_val = pcm_val >> 2; - if (pcm_val < 0) { - pcm_val = -pcm_val; - mask = 0x7F; - } else { - mask = 0xFF; - } - if (pcm_val > CLIP) pcm_val = CLIP; /* clip the magnitude */ - pcm_val += (BIAS >> 2); - - /* Convert the scaled magnitude to segment number. */ - seg = search(pcm_val, seg_uend, 8); - - /* - * Combine the sign, segment, quantization bits; - * and complement the code word. - */ - if (seg >= 8) /* out of range, return maximum value. */ - return (quint8) (0x7F ^ mask); - else { - uval = (quint8) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); - return (uval ^ mask); - } -} - -/* - * ulaw2linear() - Convert a u-law value to 16-bit linear PCM - * - * First, a biased linear code is derived from the code word. An unbiased - * output can then be obtained by subtracting 33 from the biased code. - * - * Note that this function expects to be passed the complement of the - * original code word. This is in keeping with ISDN conventions. - */ -qint16 ulaw2linear(quint8 u_val) -{ - qint16 t; - - /* Complement to obtain normal u-law value. */ - u_val = ~u_val; - - /* - * Extract and bias the quantization bits. Then - * shift up by the segment number and subtract out the bias. - */ - t = ((u_val & QUANT_MASK) << 3) + BIAS; - t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; - - return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); -} - -QXmppG711aCodec::QXmppG711aCodec(int clockrate) -{ - m_frequency = clockrate; -} - -qint64 QXmppG711aCodec::encode(QDataStream &input, QDataStream &output) -{ - qint64 samples = 0; - qint16 pcm; - while (!input.atEnd()) - { - input >> pcm; - output << linear2alaw(pcm); - ++samples; - } - return samples; -} - -qint64 QXmppG711aCodec::decode(QDataStream &input, QDataStream &output) -{ - qint64 samples = 0; - quint8 g711; - while (!input.atEnd()) - { - input >> g711; - output << alaw2linear(g711); - ++samples; - } - return samples; -} - -QXmppG711uCodec::QXmppG711uCodec(int clockrate) -{ - m_frequency = clockrate; -} - -qint64 QXmppG711uCodec::encode(QDataStream &input, QDataStream &output) -{ - qint64 samples = 0; - qint16 pcm; - while (!input.atEnd()) - { - input >> pcm; - output << linear2ulaw(pcm); - ++samples; - } - return samples; -} - -qint64 QXmppG711uCodec::decode(QDataStream &input, QDataStream &output) -{ - qint64 samples = 0; - quint8 g711; - while (!input.atEnd()) - { - input >> g711; - output << ulaw2linear(g711); - ++samples; - } - return samples; -} - -#ifdef QXMPP_USE_SPEEX -QXmppSpeexCodec::QXmppSpeexCodec(int clockrate) -{ - const SpeexMode *mode = &speex_nb_mode; - if (clockrate == 32000) - mode = &speex_uwb_mode; - else if (clockrate == 16000) - mode = &speex_wb_mode; - else if (clockrate == 8000) - mode = &speex_nb_mode; - else - qWarning() << "QXmppSpeexCodec got invalid clockrate" << clockrate; - - // encoder - encoder_bits = new SpeexBits; - speex_bits_init(encoder_bits); - encoder_state = speex_encoder_init(mode); - - // decoder - decoder_bits = new SpeexBits; - speex_bits_init(decoder_bits); - decoder_state = speex_decoder_init(mode); - - // get frame size in samples - speex_encoder_ctl(encoder_state, SPEEX_GET_FRAME_SIZE, &frame_samples); -} - -QXmppSpeexCodec::~QXmppSpeexCodec() -{ - delete encoder_bits; - delete decoder_bits; -} - -qint64 QXmppSpeexCodec::encode(QDataStream &input, QDataStream &output) -{ - QByteArray pcm_buffer(frame_samples * 2, 0); - const int length = input.readRawData(pcm_buffer.data(), pcm_buffer.size()); - if (length != pcm_buffer.size()) - { - qWarning() << "Read only read" << length << "bytes"; - return 0; - } - speex_bits_reset(encoder_bits); - speex_encode_int(encoder_state, (short*)pcm_buffer.data(), encoder_bits); - QByteArray speex_buffer(speex_bits_nbytes(encoder_bits), 0); - speex_bits_write(encoder_bits, speex_buffer.data(), speex_buffer.size()); - output.writeRawData(speex_buffer.data(), speex_buffer.size()); - return frame_samples; -} - -qint64 QXmppSpeexCodec::decode(QDataStream &input, QDataStream &output) -{ - const int length = input.device()->bytesAvailable(); - QByteArray speex_buffer(length, 0); - input.readRawData(speex_buffer.data(), speex_buffer.size()); - speex_bits_read_from(decoder_bits, speex_buffer.data(), speex_buffer.size()); - QByteArray pcm_buffer(frame_samples * 2, 0); - speex_decode_int(decoder_state, decoder_bits, (short*)pcm_buffer.data()); - output.writeRawData(pcm_buffer.data(), pcm_buffer.size()); - return frame_samples; -} - -#endif - -#ifdef QXMPP_USE_THEORA - -class QXmppTheoraDecoderPrivate -{ -public: - bool decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame); - - th_comment comment; - th_info info; - th_setup_info *setup_info; - th_dec_ctx *ctx; - - QByteArray packetBuffer; -}; - -bool QXmppTheoraDecoderPrivate::decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame) -{ - if (!ctx) - return false; - - ogg_packet packet; - packet.packet = (unsigned char*) buffer.data(); - packet.bytes = buffer.size(); - packet.b_o_s = 1; - packet.e_o_s = 0; - packet.granulepos = -1; - packet.packetno = 0; - if (th_decode_packetin(ctx, &packet, 0) != 0) { - qWarning("Theora packet could not be decoded"); - return false; - } - - th_ycbcr_buffer ycbcr_buffer; - if (th_decode_ycbcr_out(ctx, ycbcr_buffer) != 0) { - qWarning("Theora packet has no Y'CbCr"); - return false; - } - - if (info.pixel_fmt == TH_PF_420) { - if (!frame->isValid()) { - const int bytes = ycbcr_buffer[0].stride * ycbcr_buffer[0].height - + ycbcr_buffer[1].stride * ycbcr_buffer[1].height - + ycbcr_buffer[2].stride * ycbcr_buffer[2].height; - - *frame = QXmppVideoFrame(bytes, - QSize(ycbcr_buffer[0].width, ycbcr_buffer[0].height), - ycbcr_buffer[0].stride, - QXmppVideoFrame::Format_YUV420P); - } - uchar *output = frame->bits(); - for (int i = 0; i < 3; ++i) { - const int length = ycbcr_buffer[i].stride * ycbcr_buffer[i].height; - memcpy(output, ycbcr_buffer[i].data, length); - output += length; - } - return true; - } else if (info.pixel_fmt == TH_PF_422) { - if (!frame->isValid()) { - const int bytes = ycbcr_buffer[0].width * ycbcr_buffer[0].height * 2; - - *frame = QXmppVideoFrame(bytes, - QSize(ycbcr_buffer[0].width, ycbcr_buffer[0].height), - ycbcr_buffer[0].width * 2, - QXmppVideoFrame::Format_YUYV); - } - - // YUV 4:2:2 packing - const int width = ycbcr_buffer[0].width; - const int height = ycbcr_buffer[0].height; - const int y_stride = ycbcr_buffer[0].stride; - const int c_stride = ycbcr_buffer[1].stride; - const uchar *y_row = ycbcr_buffer[0].data; - const uchar *cb_row = ycbcr_buffer[1].data; - const uchar *cr_row = ycbcr_buffer[2].data; - uchar *output = frame->bits(); - for (int y = 0; y < height; ++y) { - const uchar *y_ptr = y_row; - const uchar *cb_ptr = cb_row; - const uchar *cr_ptr = cr_row; - for (int x = 0; x < width; x += 2) { - *(output++) = *(y_ptr++); - *(output++) = *(cb_ptr++); - *(output++) = *(y_ptr++); - *(output++) = *(cr_ptr++); - } - y_row += y_stride; - cb_row += c_stride; - cr_row += c_stride; - } - return true; - } else { - qWarning("Theora decoder received an unsupported frame format"); - return false; - } -} - -QXmppTheoraDecoder::QXmppTheoraDecoder() -{ - d = new QXmppTheoraDecoderPrivate; - th_comment_init(&d->comment); - th_info_init(&d->info); - d->setup_info = 0; - d->ctx = 0; -} - -QXmppTheoraDecoder::~QXmppTheoraDecoder() -{ - th_comment_clear(&d->comment); - th_info_clear(&d->info); - if (d->setup_info) - th_setup_free(d->setup_info); - if (d->ctx) - th_decode_free(d->ctx); - delete d; -} - -QXmppVideoFormat QXmppTheoraDecoder::format() const -{ - QXmppVideoFormat format; - format.setFrameSize(QSize(d->info.frame_width, d->info.frame_height)); - if (d->info.pixel_fmt == TH_PF_420) - format.setPixelFormat(QXmppVideoFrame::Format_YUV420P); - else if (d->info.pixel_fmt == TH_PF_422) - format.setPixelFormat(QXmppVideoFrame::Format_YUYV); - else - format.setPixelFormat(QXmppVideoFrame::Format_Invalid); - if (d->info.fps_denominator > 0) - format.setFrameRate(qreal(d->info.fps_numerator) / qreal(d->info.fps_denominator)); - return format; -} - -QList QXmppTheoraDecoder::handlePacket(const QXmppRtpPacket &packet) -{ - QList frames; - - // theora deframing: draft-ietf-avt-rtp-theora-00 - QDataStream stream(packet.payload); - quint32 theora_header; - stream >> theora_header; - - quint32 theora_ident = (theora_header >> 8) & 0xffffff; - Q_UNUSED(theora_ident); - quint8 theora_frag = (theora_header & 0xc0) >> 6; - quint8 theora_type = (theora_header & 0x30) >> 4; - quint8 theora_packets = (theora_header & 0x0f); - - //qDebug("ident: 0x%08x, F: %d, TDT: %d, packets: %d", theora_ident, theora_frag, theora_type, theora_packets); - - // We only handle raw theora data - if (theora_type != 0) - return frames; - - QXmppVideoFrame frame; - quint16 packetLength; - - if (theora_frag == NoFragment) { - // unfragmented packet(s) - for (int i = 0; i < theora_packets; ++i) { - stream >> packetLength; - if (packetLength > stream.device()->bytesAvailable()) { - qWarning("Theora unfragmented packet has an invalid length"); - return frames; - } - - d->packetBuffer.resize(packetLength); - stream.readRawData(d->packetBuffer.data(), packetLength); - if (d->decodeFrame(d->packetBuffer, &frame)) - frames << frame; - d->packetBuffer.resize(0); - } - } else { - // fragments - stream >> packetLength; - if (packetLength > stream.device()->bytesAvailable()) { - qWarning("Theora packet has an invalid length"); - return frames; - } - - int pos; - if (theora_frag == StartFragment) { - // start fragment - pos = 0; - d->packetBuffer.resize(packetLength); - } else { - // continuation or end fragment - pos = d->packetBuffer.size(); - d->packetBuffer.resize(pos + packetLength); - } - stream.readRawData(d->packetBuffer.data() + pos, packetLength); - - if (theora_frag == EndFragment) { - // end fragment - if (d->decodeFrame(d->packetBuffer, &frame)) - frames << frame; - d->packetBuffer.resize(0); - } - } - return frames; -} - -bool QXmppTheoraDecoder::setParameters(const QMap ¶meters) -{ - QByteArray config = QByteArray::fromBase64(parameters.value("configuration").toAscii()); - QDataStream stream(config); - const QIODevice *device = stream.device(); - - if (device->bytesAvailable() < 4) { - qWarning("Theora configuration is too small"); - return false; - } - - // Process packed headers - int done = 0; - quint32 header_count; - stream >> header_count; - for (quint32 i = 0; i < header_count; ++i) { - if (device->bytesAvailable() < 6) { - qWarning("Theora configuration is too small"); - return false; - } - QByteArray ident(3, 0); - quint16 length; - quint8 h_count; - - stream.readRawData(ident.data(), ident.size()); - stream >> length; - stream >> h_count; -#ifdef QXMPP_DEBUG_THEORA - qDebug("Theora packed header %u ident=%s bytes=%u count=%u", i, ident.toHex().data(), length, h_count); -#endif - - // get header sizes - QList h_sizes; - for (int h = 0; h < h_count; ++h) { - quint16 h_size = 0; - quint8 b; - do { - if (device->bytesAvailable() < 1) { - qWarning("Theora configuration is too small"); - return false; - } - stream >> b; - h_size = (h_size << 7) | (b & 0x7f); - } while (b & 0x80); - h_sizes << h_size; -#ifdef QXMPP_DEBUG_THEORA - qDebug("Theora header %d size %u", h_sizes.size() - 1, h_sizes.last()); -#endif - length -= h_size; - } - h_sizes << length; -#ifdef QXMPP_DEBUG_THEORA - qDebug("Theora header %d size %u", h_sizes.size() - 1, h_sizes.last()); -#endif - - // decode headers - ogg_packet packet; - packet.b_o_s = 1; - packet.e_o_s = 0; - packet.granulepos = -1; - packet.packetno = 0; - - foreach (int h_size, h_sizes) { - if (device->bytesAvailable() < h_size) { - qWarning("Theora configuration is too small"); - return false; - } - - packet.packet = (unsigned char*) (config.data() + device->pos()); - packet.bytes = h_size; - int ret = th_decode_headerin(&d->info, &d->comment, &d->setup_info, &packet); - if (ret < 0) { - qWarning("Theora header could not be decoded"); - return false; - } - done += ret; - stream.skipRawData(h_size); - } - } - - // check for completion - if (done < 3) { - qWarning("Theora configuration did not contain enough headers"); - return false; - } - -#ifdef QXMPP_DEBUG_THEORA - qDebug("Theora frame_width %i, frame_height %i, colorspace %i, pixel_fmt: %i, target_bitrate: %i, quality: %i, keyframe_granule_shift: %i", - d->info.frame_width, - d->info.frame_height, - d->info.colorspace, - d->info.pixel_fmt, - d->info.target_bitrate, - d->info.quality, - d->info.keyframe_granule_shift); -#endif - if (d->info.pixel_fmt != TH_PF_420 && d->info.pixel_fmt != TH_PF_422) { - qWarning("Theora frames have an unsupported pixel format %d", d->info.pixel_fmt); - return false; - } - if (d->ctx) - th_decode_free(d->ctx); - d->ctx = th_decode_alloc(&d->info, d->setup_info); - if (!d->ctx) { - qWarning("Theora decoder could not be allocated"); - return false; - } - return true; -} - -class QXmppTheoraEncoderPrivate -{ -public: - void writeFragment(QDataStream &stream, FragmentType frag_type, quint8 theora_packets, const char *data, quint16 length); - - th_comment comment; - th_info info; - th_setup_info *setup_info; - th_enc_ctx *ctx; - th_ycbcr_buffer ycbcr_buffer; - - QByteArray buffer; - QByteArray configuration; - QByteArray ident; -}; - -void QXmppTheoraEncoderPrivate::writeFragment(QDataStream &stream, FragmentType frag_type, quint8 theora_packets, const char *data, quint16 length) -{ - // theora framing: draft-ietf-avt-rtp-theora-00 - const quint8 theora_type = 0; // raw data - stream.writeRawData(ident.constData(), ident.size()); - stream << quint8(((frag_type << 6) & 0xc0) | - ((theora_type << 4) & 0x30) | - (theora_packets & 0x0f)); - stream << quint16(length); - stream.writeRawData(data, length); -} - -QXmppTheoraEncoder::QXmppTheoraEncoder() -{ - d = new QXmppTheoraEncoderPrivate; - d->ident = QByteArray("\xc3\x45\xae"); - th_comment_init(&d->comment); - th_info_init(&d->info); - d->setup_info = 0; - d->ctx = 0; -} - -QXmppTheoraEncoder::~QXmppTheoraEncoder() -{ - th_comment_clear(&d->comment); - th_info_clear(&d->info); - if (d->setup_info) - th_setup_free(d->setup_info); - if (d->ctx) - th_encode_free(d->ctx); - delete d; -} - -bool QXmppTheoraEncoder::setFormat(const QXmppVideoFormat &format) -{ - const QXmppVideoFrame::PixelFormat pixelFormat = format.pixelFormat(); - if ((pixelFormat != QXmppVideoFrame::Format_YUV420P) && - (pixelFormat != QXmppVideoFrame::Format_YUYV)) { - qWarning("Theora encoder does not support the given format"); - return false; - } - - d->info.frame_width = format.frameSize().width(); - d->info.frame_height = format.frameSize().height(); - d->info.pic_height = format.frameSize().height(); - d->info.pic_width = format.frameSize().width(); - d->info.pic_x = 0; - d->info.pic_y = 0; - d->info.colorspace = TH_CS_UNSPECIFIED; - d->info.target_bitrate = 0; - d->info.quality = 48; - d->info.keyframe_granule_shift = 6; - - // FIXME: how do we handle floating point frame rates? - d->info.fps_numerator = format.frameRate(); - d->info.fps_denominator = 1; - - if (pixelFormat == QXmppVideoFrame::Format_YUV420P) { - d->info.pixel_fmt = TH_PF_420; - d->ycbcr_buffer[0].width = d->info.frame_width; - d->ycbcr_buffer[0].height = d->info.frame_height; - d->ycbcr_buffer[1].width = d->ycbcr_buffer[0].width / 2; - d->ycbcr_buffer[1].height = d->ycbcr_buffer[0].height / 2; - d->ycbcr_buffer[2].width = d->ycbcr_buffer[1].width; - d->ycbcr_buffer[2].height = d->ycbcr_buffer[1].height; - } else if (pixelFormat == QXmppVideoFrame::Format_YUYV) { - d->info.pixel_fmt = TH_PF_422; - d->buffer.resize(d->info.frame_width * d->info.frame_height * 2); - d->ycbcr_buffer[0].width = d->info.frame_width; - d->ycbcr_buffer[0].height = d->info.frame_height; - d->ycbcr_buffer[0].stride = d->info.frame_width; - d->ycbcr_buffer[0].data = (uchar*) d->buffer.data(); - d->ycbcr_buffer[1].width = d->ycbcr_buffer[0].width / 2; - d->ycbcr_buffer[1].height = d->ycbcr_buffer[0].height; - d->ycbcr_buffer[1].stride = d->ycbcr_buffer[0].stride / 2; - d->ycbcr_buffer[1].data = d->ycbcr_buffer[0].data + d->ycbcr_buffer[0].stride * d->ycbcr_buffer[0].height; - d->ycbcr_buffer[2].width = d->ycbcr_buffer[1].width; - d->ycbcr_buffer[2].height = d->ycbcr_buffer[1].height; - d->ycbcr_buffer[2].stride = d->ycbcr_buffer[1].stride; - d->ycbcr_buffer[2].data = d->ycbcr_buffer[1].data + d->ycbcr_buffer[1].stride * d->ycbcr_buffer[1].height; - } - - // create encoder - if (d->ctx) { - th_encode_free(d->ctx); - d->ctx = 0; - } - d->ctx = th_encode_alloc(&d->info); - if (!d->ctx) { - qWarning("Theora encoder could not be allocated"); - return false; - } - - // fetch headers - QList headers; - ogg_packet packet; - while (th_encode_flushheader(d->ctx, &d->comment, &packet) > 0) - headers << QByteArray((const char*)packet.packet, packet.bytes); - - // store configuration - d->configuration.clear(); - QDataStream stream(&d->configuration, QIODevice::WriteOnly); - stream << quint32(1); - - quint16 length = 0; - foreach (const QByteArray &header, headers) - length += header.size(); - - quint8 h_count = headers.size() - 1; - stream.writeRawData(d->ident.constData(), d->ident.size()); - stream << length; - stream << h_count; -#ifdef QXMPP_DEBUG_THEORA - qDebug("Theora packed header %u ident=%s bytes=%u count=%u", 0, d->ident.toHex().data(), length, h_count); -#endif - - // write header sizes - for (int h = 0; h < h_count; ++h) { - quint16 h_size = headers[h].size(); - do { - quint8 b = (h_size & 0x7f); - h_size >>= 7; - if (h_size) - b |= 0x80; - stream << b; - } while (h_size); - } - - // write headers - for (int h = 0; h < headers.size(); ++h) { -#ifdef QXMPP_DEBUG_THEORA - qDebug("Header %d size %d", h, headers[h].size()); -#endif - stream.writeRawData(headers[h].data(), headers[h].size()); - } - - return true; -} - -QList QXmppTheoraEncoder::handleFrame(const QXmppVideoFrame &frame) -{ - QList packets; - const int PACKET_MAX = 1388; - - if (!d->ctx) - return packets; - - if (d->info.pixel_fmt == TH_PF_420) { - d->ycbcr_buffer[0].stride = frame.bytesPerLine(); - d->ycbcr_buffer[0].data = (unsigned char*) frame.bits(); - d->ycbcr_buffer[1].stride = d->ycbcr_buffer[0].stride / 2; - d->ycbcr_buffer[1].data = d->ycbcr_buffer[0].data + d->ycbcr_buffer[0].stride * d->ycbcr_buffer[0].height; - d->ycbcr_buffer[2].stride = d->ycbcr_buffer[1].stride; - d->ycbcr_buffer[2].data = d->ycbcr_buffer[1].data + d->ycbcr_buffer[1].stride * d->ycbcr_buffer[1].height; - } else if (d->info.pixel_fmt == TH_PF_422) { - // YUV 4:2:2 unpacking - const int width = frame.width(); - const int height = frame.height(); - const int stride = frame.bytesPerLine(); - const uchar *row = frame.bits(); - uchar *y_out = d->ycbcr_buffer[0].data; - uchar *cb_out = d->ycbcr_buffer[1].data; - uchar *cr_out = d->ycbcr_buffer[2].data; - for (int y = 0; y < height; ++y) { - const uchar *ptr = row; - for (int x = 0; x < width; x += 2) { - *(y_out++) = *(ptr++); - *(cb_out++) = *(ptr++); - *(y_out++) = *(ptr++); - *(cr_out++) = *(ptr++); - } - row += stride; - } - } else { - qWarning("Theora encoder received an unsupported frame format"); - return packets; - } - - if (th_encode_ycbcr_in(d->ctx, d->ycbcr_buffer) != 0) { - qWarning("Theora encoder could not handle frame"); - return packets; - } - - QByteArray payload; - ogg_packet packet; - while (th_encode_packetout(d->ctx, 0, &packet) > 0) { -#ifdef QXMPP_DEBUG_THEORA - qDebug("Theora encoded packet %d bytes", packet.bytes); -#endif - QDataStream stream(&payload, QIODevice::WriteOnly); - const char *data = (const char*) packet.packet; - int size = packet.bytes; - if (size <= PACKET_MAX) { - // no fragmentation - stream.device()->reset(); - payload.resize(0); - d->writeFragment(stream, NoFragment, 1, data, size); - packets << payload; - } else { - // fragmentation - FragmentType frag_type = StartFragment; - while (size) { - const int length = qMin(PACKET_MAX, size); - stream.device()->reset(); - payload.resize(0); - d->writeFragment(stream, frag_type, 0, data, length); - data += length; - size -= length; - frag_type = (size > PACKET_MAX) ? MiddleFragment : EndFragment; - packets << payload; - } - } - } - - return packets; -} - -QMap QXmppTheoraEncoder::parameters() const -{ - QMap params; - if (d->ctx) { - params.insert("delivery-method", "inline"); - params.insert("configuration", d->configuration.toBase64()); - } - return params; -} - -#endif - -#ifdef QXMPP_USE_VPX - -class QXmppVpxDecoderPrivate -{ -public: - bool decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame); - - vpx_codec_ctx_t codec; - QByteArray packetBuffer; -}; - -bool QXmppVpxDecoderPrivate::decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame) -{ - if (vpx_codec_decode(&codec, (const uint8_t*)buffer.constData(), buffer.size(), NULL, 0) != VPX_CODEC_OK) { - qWarning("Vpx packet could not be decoded: %s", vpx_codec_error_detail(&codec)); - return false; - } - - vpx_codec_iter_t iter = NULL; - vpx_image_t *img; - while ((img = vpx_codec_get_frame(&codec, &iter))) { - if (img->fmt == VPX_IMG_FMT_I420) { - if (!frame->isValid()) { - const int bytes = img->d_w * img->d_h * 3 / 2; - - *frame = QXmppVideoFrame(bytes, - QSize(img->d_w, img->d_h), - img->d_w, - QXmppVideoFrame::Format_YUV420P); - } - uchar *output = frame->bits(); - - for (int i = 0; i < 3; ++i) { - uchar *input = img->planes[i]; - const int div = (i == 0) ? 1 : 2; - for (unsigned int y = 0; y < img->d_h / div; ++y) { - memcpy(output, input, img->d_w / div); - input += img->stride[i]; - output += img->d_w / div; - } - } - } else { - qWarning("Vpx decoder received an unsupported frame format: %d", img->fmt); - } - } - - return true; -} - -QXmppVpxDecoder::QXmppVpxDecoder() -{ - d = new QXmppVpxDecoderPrivate; - if (vpx_codec_dec_init(&d->codec, vpx_codec_vp8_dx(), NULL, 0) != VPX_CODEC_OK) { - qWarning("Vpx decoder could not be initialised"); - } -} - -QXmppVpxDecoder::~QXmppVpxDecoder() -{ - vpx_codec_destroy(&d->codec); - delete d; -} - -QXmppVideoFormat QXmppVpxDecoder::format() const -{ - QXmppVideoFormat format; - format.setFrameRate(15.0); - format.setFrameSize(QSize(320, 240)); - format.setPixelFormat(QXmppVideoFrame::Format_YUV420P); - return format; -} - -QList QXmppVpxDecoder::handlePacket(const QXmppRtpPacket &packet) -{ - QList frames; - - // vp8 deframing: http://tools.ietf.org/html/draft-westin-payload-vp8-00 - QDataStream stream(packet.payload); - quint8 vpx_header; - stream >> vpx_header; - - const bool have_id = (vpx_header & 0x10) != 0; - const quint8 frag_type = (vpx_header & 0x6) >> 1; - if (have_id) { - qWarning("Vpx decoder does not support pictureId yet"); - return frames; - } - - const int packetLength = packet.payload.size() - 1; -#ifdef QXMPP_DEBUG_VPX - qDebug("Vpx fragment FI: %d, size %d", frag_type, packetLength); -#endif - - QXmppVideoFrame frame; - - if (frag_type == NoFragment) { - // unfragmented packet - if (d->decodeFrame(packet.payload.mid(1), &frame)) - frames << frame; - d->packetBuffer.resize(0); - } else { - // fragments - if (frag_type == StartFragment) { - // start fragment - d->packetBuffer = packet.payload.mid(1); - } else { - // continuation or end fragment - const int packetPos = d->packetBuffer.size(); - d->packetBuffer.resize(packetPos + packetLength); - stream.readRawData(d->packetBuffer.data() + packetPos, packetLength); - } - - if (frag_type == EndFragment) { - // end fragment - if (d->decodeFrame(d->packetBuffer, &frame)) - frames << frame; - d->packetBuffer.resize(0); - } - - } - - return frames; -} - -bool QXmppVpxDecoder::setParameters(const QMap ¶meters) -{ - return true; -} - -class QXmppVpxEncoderPrivate -{ -public: - void writeFragment(QDataStream &stream, FragmentType frag_type, const char *data, quint16 length); - - vpx_codec_ctx_t codec; - vpx_codec_enc_cfg_t cfg; - vpx_image_t *imageBuffer; - int frameCount; -}; - -void QXmppVpxEncoderPrivate::writeFragment(QDataStream &stream, FragmentType frag_type, const char *data, quint16 length) -{ - // vp8 framing: http://tools.ietf.org/html/draft-westin-payload-vp8-00 -#ifdef QXMPP_DEBUG_VPX - qDebug("Vpx encoder writing packet frag: %i, size: %u", frag_type, length); -#endif - stream << quint8(((frag_type << 1) & 0x6) | - (frag_type == NoFragment || frag_type == StartFragment)); - stream.writeRawData(data, length); -} - -QXmppVpxEncoder::QXmppVpxEncoder() -{ - d = new QXmppVpxEncoderPrivate; - d->frameCount = 0; - d->imageBuffer = 0; - vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &d->cfg, 0); -} - -QXmppVpxEncoder::~QXmppVpxEncoder() -{ - vpx_codec_destroy(&d->codec); - if (d->imageBuffer) - vpx_img_free(d->imageBuffer); - delete d; -} - -bool QXmppVpxEncoder::setFormat(const QXmppVideoFormat &format) -{ - const QXmppVideoFrame::PixelFormat pixelFormat = format.pixelFormat(); - if (pixelFormat != QXmppVideoFrame::Format_YUYV) { - qWarning("Vpx encoder does not support the given format"); - return false; - } - - d->cfg.rc_target_bitrate = format.frameSize().width() * format.frameSize().height() * d->cfg.rc_target_bitrate / d->cfg.g_w / d->cfg.g_h; - d->cfg.g_w = format.frameSize().width(); - d->cfg.g_h = format.frameSize().height(); - if (vpx_codec_enc_init(&d->codec, vpx_codec_vp8_cx(), &d->cfg, 0) != VPX_CODEC_OK) { - qWarning("Vpx encoder could not be initialised"); - return false; - } - - d->imageBuffer = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, - format.frameSize().width(), format.frameSize().height(), 1); - return true; -} - -QList QXmppVpxEncoder::handleFrame(const QXmppVideoFrame &frame) -{ - const int PACKET_MAX = 1388; - QList packets; - - // try to encode frame - if (frame.pixelFormat() == QXmppVideoFrame::Format_YUYV) { - // YUYV -> YUV420P - const int width = frame.width(); - const int height = frame.height(); - const int stride = frame.bytesPerLine(); - const uchar *row = frame.bits(); - uchar *y_row = d->imageBuffer->planes[VPX_PLANE_Y]; - uchar *cb_row = d->imageBuffer->planes[VPX_PLANE_U]; - uchar *cr_row = d->imageBuffer->planes[VPX_PLANE_V]; - for (int y = 0; y < height; y += 2) { - // odd row - const uchar *ptr = row; - uchar *y_out = y_row; - uchar *cb_out = cb_row; - uchar *cr_out = cr_row; - for (int x = 0; x < width; x += 2) { - *(y_out++) = *(ptr++); - *(cb_out++) = *(ptr++); - *(y_out++) = *(ptr++); - *(cr_out++) = *(ptr++); - } - row += stride; - y_row += d->imageBuffer->stride[VPX_PLANE_Y]; - cb_row += d->imageBuffer->stride[VPX_PLANE_U]; - cr_row += d->imageBuffer->stride[VPX_PLANE_V]; - - // even row - ptr = row; - y_out = y_row; - for (int x = 0; x < width; x += 2) { - *(y_out++) = *(ptr++); - ptr++; - *(y_out++) = *(ptr++); - ptr++; - } - row += stride; - y_row += d->imageBuffer->stride[VPX_PLANE_Y]; - } - } else { - qWarning("Vpx encoder does not support the given format"); - return packets; - } - - if (vpx_codec_encode(&d->codec, d->imageBuffer, d->frameCount, 1, 0, VPX_DL_REALTIME) != VPX_CODEC_OK) { - qWarning("Vpx encoder could not handle frame: %s", vpx_codec_error_detail(&d->codec)); - return packets; - } - - // extract data - QByteArray payload; - vpx_codec_iter_t iter = NULL; - const vpx_codec_cx_pkt_t *pkt; - while ((pkt = vpx_codec_get_cx_data(&d->codec, &iter))) { - if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { -#ifdef QXMPP_DEBUG_VPX - qDebug("Vpx encoded packet %lu bytes", pkt->data.frame.sz); -#endif - QDataStream stream(&payload, QIODevice::WriteOnly); - const char *data = (const char*) pkt->data.frame.buf; - int size = pkt->data.frame.sz; - if (size <= PACKET_MAX) { - // no fragmentation - stream.device()->reset(); - payload.resize(0); - d->writeFragment(stream, NoFragment, data, size); - packets << payload; - } else { - // fragmentation - FragmentType frag_type = StartFragment; - while (size) { - const int length = qMin(PACKET_MAX, size); - stream.device()->reset(); - payload.resize(0); - d->writeFragment(stream, frag_type, data, length); - data += length; - size -= length; - frag_type = (size > PACKET_MAX) ? MiddleFragment : EndFragment; - packets << payload; - } - } - } - } - d->frameCount++; - - return packets; -} - -QMap QXmppVpxEncoder::parameters() const -{ - return QMap(); -} - -#endif diff --git a/src/QXmppCodec.h b/src/QXmppCodec.h deleted file mode 100644 index 61dd45a2..00000000 --- a/src/QXmppCodec.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPCODEC_H -#define QXMPPCODEC_H - -#include - -class QXmppRtpPacket; -class QXmppVideoFormat; -class QXmppVideoFrame; - -/// \brief The QXmppCodec class is the base class for audio codecs capable of -/// encoding and decoding audio samples. -/// -/// Samples must be 16-bit little endian. - -class QXmppCodec -{ -public: - /// Reads samples from the input stream, encodes them and writes the - /// encoded data to the output stream. - virtual qint64 encode(QDataStream &input, QDataStream &output) = 0; - - /// Reads encoded data from the input stream, decodes it and writes the - /// decoded samples to the output stream. - virtual qint64 decode(QDataStream &input, QDataStream &output) = 0; -}; - -/// \internal -/// -/// The QXmppG711aCodec class represent a G.711 a-law PCM codec. - -class QXmppG711aCodec : public QXmppCodec -{ -public: - QXmppG711aCodec(int clockrate); - - qint64 encode(QDataStream &input, QDataStream &output); - qint64 decode(QDataStream &input, QDataStream &output); - -private: - int m_frequency; -}; - -/// \internal -/// -/// The QXmppG711uCodec class represent a G.711 u-law PCM codec. - -class QXmppG711uCodec : public QXmppCodec -{ -public: - QXmppG711uCodec(int clockrate); - - qint64 encode(QDataStream &input, QDataStream &output); - qint64 decode(QDataStream &input, QDataStream &output); - -private: - int m_frequency; -}; - -#ifdef QXMPP_USE_SPEEX -typedef struct SpeexBits SpeexBits; - -/// \internal -/// -/// The QXmppSpeexCodec class represent a SPEEX codec. - -class QXmppSpeexCodec : public QXmppCodec -{ -public: - QXmppSpeexCodec(int clockrate); - ~QXmppSpeexCodec(); - - qint64 encode(QDataStream &input, QDataStream &output); - qint64 decode(QDataStream &input, QDataStream &output); - -private: - SpeexBits *encoder_bits; - void *encoder_state; - SpeexBits *decoder_bits; - void *decoder_state; - int frame_samples; -}; -#endif - -/// \brief The QXmppVideoDecoder class is the base class for video decoders. -/// - -class QXmppVideoDecoder -{ -public: - virtual QXmppVideoFormat format() const = 0; - virtual QList handlePacket(const QXmppRtpPacket &packet) = 0; - virtual bool setParameters(const QMap ¶meters) = 0; -}; - -class QXmppVideoEncoder -{ -public: - virtual bool setFormat(const QXmppVideoFormat &format) = 0; - virtual QList handleFrame(const QXmppVideoFrame &frame) = 0; - virtual QMap parameters() const = 0; -}; - -#ifdef QXMPP_USE_THEORA -class QXmppTheoraDecoderPrivate; -class QXmppTheoraEncoderPrivate; - -class QXmppTheoraDecoder : public QXmppVideoDecoder -{ -public: - QXmppTheoraDecoder(); - ~QXmppTheoraDecoder(); - - QXmppVideoFormat format() const; - QList handlePacket(const QXmppRtpPacket &packet); - bool setParameters(const QMap ¶meters); - -private: - QXmppTheoraDecoderPrivate *d; -}; - -class QXmppTheoraEncoder : public QXmppVideoEncoder -{ -public: - QXmppTheoraEncoder(); - ~QXmppTheoraEncoder(); - - bool setFormat(const QXmppVideoFormat &format); - QList handleFrame(const QXmppVideoFrame &frame); - QMap parameters() const; - -private: - QXmppTheoraEncoderPrivate *d; -}; -#endif - -#ifdef QXMPP_USE_VPX -class QXmppVpxDecoderPrivate; -class QXmppVpxEncoderPrivate; - -class QXmppVpxDecoder : public QXmppVideoDecoder -{ -public: - QXmppVpxDecoder(); - ~QXmppVpxDecoder(); - - QXmppVideoFormat format() const; - QList handlePacket(const QXmppRtpPacket &packet); - bool setParameters(const QMap ¶meters); - -private: - QXmppVpxDecoderPrivate *d; -}; - -class QXmppVpxEncoder : public QXmppVideoEncoder -{ -public: - QXmppVpxEncoder(); - ~QXmppVpxEncoder(); - - bool setFormat(const QXmppVideoFormat &format); - QList handleFrame(const QXmppVideoFrame &frame); - QMap parameters() const; - -private: - QXmppVpxEncoderPrivate *d; -}; -#endif - -#endif diff --git a/src/QXmppConstants.cpp b/src/QXmppConstants.cpp deleted file mode 100644 index c77859b6..00000000 --- a/src/QXmppConstants.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#include "QXmppConstants.h" - -const char* ns_stream = "http://etherx.jabber.org/streams"; -const char* ns_client = "jabber:client"; -const char* ns_server = "jabber:server"; -const char* ns_server_dialback = "jabber:server:dialback"; -const char* ns_roster = "jabber:iq:roster"; -const char* ns_tls = "urn:ietf:params:xml:ns:xmpp-tls"; -const char* ns_sasl = "urn:ietf:params:xml:ns:xmpp-sasl"; -const char* ns_bind = "urn:ietf:params:xml:ns:xmpp-bind"; -const char* ns_session = "urn:ietf:params:xml:ns:xmpp-session"; -const char* ns_stanza = "urn:ietf:params:xml:ns:xmpp-stanzas"; -const char* ns_vcard = "vcard-temp"; -const char* ns_vcard_update = "vcard-temp:x:update"; -const char* ns_auth = "jabber:iq:auth"; -const char* ns_authFeature = "http://jabber.org/features/iq-auth"; -const char* ns_capabilities = "http://jabber.org/protocol/caps"; -const char* ns_compress = "http://jabber.org/protocol/compress"; -const char* ns_compressFeature = "http://jabber.org/features/compress"; -const char* ns_disco_info = "http://jabber.org/protocol/disco#info"; -const char* ns_disco_items = "http://jabber.org/protocol/disco#items"; -const char* ns_ibb = "http://jabber.org/protocol/ibb"; -const char* ns_rpc = "jabber:iq:rpc"; -const char *ns_ping = "urn:xmpp:ping"; -const char *ns_conference = "jabber:x:conference"; -const char *ns_message_receipts = "urn:xmpp:receipts"; -const char *ns_delayed_delivery = "urn:xmpp:delay"; -const char *ns_legacy_delayed_delivery = "jabber:x:delay"; -const char *ns_muc = "http://jabber.org/protocol/muc"; -const char *ns_muc_admin = "http://jabber.org/protocol/muc#admin"; -const char *ns_muc_owner = "http://jabber.org/protocol/muc#owner"; -const char *ns_muc_user = "http://jabber.org/protocol/muc#user"; -const char *ns_chat_states = "http://jabber.org/protocol/chatstates"; -const char *ns_stream_initiation = "http://jabber.org/protocol/si"; -const char *ns_stream_initiation_file_transfer = "http://jabber.org/protocol/si/profile/file-transfer"; -const char *ns_feature_negotiation = "http://jabber.org/protocol/feature-neg"; -const char *ns_bytestreams = "http://jabber.org/protocol/bytestreams"; -// XEP-0092: Software Version -const char *ns_version = "jabber:iq:version"; -const char *ns_data = "jabber:x:data"; -// XEP-0166: Jingle -const char *ns_jingle = "urn:xmpp:jingle:1"; -const char *ns_jingle_raw_udp = "urn:xmpp:jingle:transports:raw-udp:1"; -const char* ns_jingle_ice_udp = "urn:xmpp:jingle:transports:ice-udp:1"; -const char *ns_jingle_rtp = "urn:xmpp:jingle:apps:rtp:1"; -const char *ns_jingle_rtp_audio = "urn:xmpp:jingle:apps:rtp:audio"; -const char *ns_jingle_rtp_video = "urn:xmpp:jingle:apps:rtp:video"; -// XEP-0202: Entity Time -const char *ns_entity_time = "urn:xmpp:time"; -// XEP-0224: Attention -const char *ns_attention = "urn:xmpp:attention:0"; diff --git a/src/QXmppConstants.h b/src/QXmppConstants.h deleted file mode 100644 index 909bddd9..00000000 --- a/src/QXmppConstants.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPCONSTANTS_H -#define QXMPPCONSTANTS_H - -extern const char* ns_stream; -extern const char* ns_client; -extern const char* ns_server; -extern const char* ns_server_dialback; -extern const char* ns_roster; -extern const char* ns_tls; -extern const char* ns_sasl; -extern const char* ns_bind; -extern const char* ns_session; -extern const char* ns_stanza; -extern const char* ns_vcard; -extern const char* ns_vcard_update; -extern const char* ns_auth; -extern const char* ns_authFeature; -extern const char* ns_capabilities; -extern const char* ns_compress; -extern const char* ns_compressFeature; -extern const char* ns_disco_info; -extern const char* ns_disco_items; -extern const char* ns_ibb; -extern const char* ns_rpc; -extern const char* ns_ping; -extern const char *ns_conference; -extern const char *ns_message_receipts; -extern const char *ns_delayed_delivery; -extern const char *ns_legacy_delayed_delivery; -extern const char *ns_muc; -extern const char *ns_muc_admin; -extern const char *ns_muc_owner; -extern const char *ns_muc_user; -extern const char *ns_chat_states; -extern const char *ns_stream_initiation; -extern const char *ns_stream_initiation_file_transfer; -extern const char *ns_feature_negotiation; -extern const char *ns_bytestreams; -extern const char *ns_version; -extern const char *ns_data; -extern const char *ns_jingle; -extern const char* ns_jingle_ice_udp; -extern const char* ns_jingle_raw_udp; -extern const char *ns_jingle_rtp; -extern const char *ns_jingle_rtp_audio; -extern const char *ns_jingle_rtp_video; -extern const char *ns_entity_time; -extern const char *ns_attention; - -#endif // QXMPPCONSTANTS_H diff --git a/src/QXmppDataForm.cpp b/src/QXmppDataForm.cpp deleted file mode 100644 index aab3857d..00000000 --- a/src/QXmppDataForm.cpp +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include -#include -#include - -#include "QXmppConstants.h" -#include "QXmppDataForm.h" -#include "QXmppUtils.h" - -struct field_type { - QXmppDataForm::Field::Type type; - const char *str; -}; - -static field_type field_types[] = { - {QXmppDataForm::Field::BooleanField, "boolean"}, - {QXmppDataForm::Field::FixedField, "fixed"}, - {QXmppDataForm::Field::HiddenField, "hidden"}, - {QXmppDataForm::Field::JidMultiField, "jid-multi"}, - {QXmppDataForm::Field::JidSingleField, "jid-single"}, - {QXmppDataForm::Field::ListMultiField, "list-multi"}, - {QXmppDataForm::Field::ListSingleField, "list-single"}, - {QXmppDataForm::Field::TextMultiField, "text-multi"}, - {QXmppDataForm::Field::TextPrivateField, "text-private"}, - {QXmppDataForm::Field::TextSingleField, "text-single"}, - {static_cast(-1), NULL}, -}; - -/// Constructs a QXmppDataForm::Field of the specified \a type. -/// -/// \param type - -QXmppDataForm::Field::Field(QXmppDataForm::Field::Type type) - : m_required(false), - m_type(type) -{ -} - -/// Returns the field's description. - -QString QXmppDataForm::Field::description() const -{ - return m_description; -} - -/// Sets the field's description. -/// -/// \param description - -void QXmppDataForm::Field::setDescription(const QString &description) -{ - m_description = description; -} - -/// Returns the field's key. - -QString QXmppDataForm::Field::key() const -{ - return m_key; -} - -/// Sets the field's key. -/// -/// \param key - -void QXmppDataForm::Field::setKey(const QString &key) -{ - m_key = key; -} - -/// Returns the field's label. - -QString QXmppDataForm::Field::label() const -{ - return m_label; -} - -/// Sets the field's label. -/// -/// \param label - -void QXmppDataForm::Field::setLabel(const QString &label) -{ - m_label = label; -} - -/// Returns the field's options. - -QList > QXmppDataForm::Field::options() const -{ - return m_options; -} - -/// Sets the field's options. -/// -/// \param options - -void QXmppDataForm::Field::setOptions(const QList > &options) -{ - m_options = options; -} - -/// Returns true if the field is required, false otherwise. - -bool QXmppDataForm::Field::isRequired() const -{ - return m_required; -} - -/// Set to true if the field is required, false otherwise. -/// -/// \param required - -void QXmppDataForm::Field::setRequired(bool required) -{ - m_required = required; -} - -/// Returns the field's type. - -QXmppDataForm::Field::Type QXmppDataForm::Field::type() const -{ - return m_type; -} - -/// Sets the field's type. -/// -/// \param type - -void QXmppDataForm::Field::setType(QXmppDataForm::Field::Type type) -{ - m_type = type; -} - -/// Returns the field's value. - -QVariant QXmppDataForm::Field::value() const -{ - return m_value; -} - -/// Sets the field's value. -/// -/// \param value - -void QXmppDataForm::Field::setValue(const QVariant &value) -{ - m_value = value; -} - -/// Constructs a QXmppDataForm of the specified \a type. -/// -/// \param type - -QXmppDataForm::QXmppDataForm(QXmppDataForm::Type type) - : m_type(type) -{ -} - -/// Returns the form's fields. - -QList QXmppDataForm::fields() const -{ - return m_fields; -} - -/// Returns the form's fields by reference. - -QList &QXmppDataForm::fields() -{ - return m_fields; -} - -/// Sets the form's fields. -/// -/// \param fields - -void QXmppDataForm::setFields(const QList &fields) -{ - m_fields = fields; -} - -/// Returns the form's instructions. - -QString QXmppDataForm::instructions() const -{ - return m_instructions; -} - -/// Sets the form's instructions. -/// -/// \param instructions - -void QXmppDataForm::setInstructions(const QString &instructions) -{ - m_instructions = instructions; -} - -/// Returns the form's title. - -QString QXmppDataForm::title() const -{ - return m_title; -} - -/// Sets the form's title. -/// -/// \param title - -void QXmppDataForm::setTitle(const QString &title) -{ - m_title = title; -} - -/// Returns the form's type. - -QXmppDataForm::Type QXmppDataForm::type() const -{ - return m_type; -} - -/// Sets the form's type. -/// -/// \param type - -void QXmppDataForm::setType(QXmppDataForm::Type type) -{ - m_type = type; -} - -/// Returns true if the form has an unknown type. - -bool QXmppDataForm::isNull() const -{ - return m_type == QXmppDataForm::None; -} - -void QXmppDataForm::parse(const QDomElement &element) -{ - if (element.isNull()) - return; - - /* form type */ - const QString typeStr = element.attribute("type"); - if (typeStr == "form") - m_type = QXmppDataForm::Form; - else if (typeStr == "submit") - m_type = QXmppDataForm::Submit; - else if (typeStr == "cancel") - m_type = QXmppDataForm::Cancel; - else if (typeStr == "result") - m_type = QXmppDataForm::Result; - else - { - qWarning() << "Unknown form type" << typeStr; - return; - } - - /* form properties */ - m_title = element.firstChildElement("title").text(); - m_instructions = element.firstChildElement("instructions").text(); - - QDomElement fieldElement = element.firstChildElement("field"); - while (!fieldElement.isNull()) - { - QXmppDataForm::Field field; - - /* field type */ - QXmppDataForm::Field::Type type = QXmppDataForm::Field::TextSingleField; - const QString typeStr = fieldElement.attribute("type"); - struct field_type *ptr; - for (ptr = field_types; ptr->str; ptr++) - { - if (typeStr == ptr->str) - { - type = ptr->type; - break; - } - } - field.setType(type); - - /* field attributes */ - field.setLabel(fieldElement.attribute("label")); - field.setKey(fieldElement.attribute("var")); - - /* field value(s) */ - if (type == QXmppDataForm::Field::BooleanField) - { - const QString valueStr = fieldElement.firstChildElement("value").text(); - field.setValue(valueStr == "1" || valueStr == "true"); - } - else if (type == QXmppDataForm::Field::ListMultiField || - type == QXmppDataForm::Field::JidMultiField || - type == QXmppDataForm::Field::TextMultiField) - { - QStringList values; - QDomElement valueElement = fieldElement.firstChildElement("value"); - while (!valueElement.isNull()) - { - values.append(valueElement.text()); - valueElement = valueElement.nextSiblingElement("value"); - } - field.setValue(values); - } - else - { - field.setValue(fieldElement.firstChildElement("value").text()); - } - - /* field options */ - if (type == QXmppDataForm::Field::ListMultiField || - type == QXmppDataForm::Field::ListSingleField) - { - QList > options; - QDomElement optionElement = fieldElement.firstChildElement("option"); - while (!optionElement.isNull()) - { - options.append(QPair(optionElement.attribute("label"), - optionElement.firstChildElement("value").text())); - optionElement = optionElement.nextSiblingElement("option"); - } - field.setOptions(options); - } - - /* other properties */ - field.setDescription(fieldElement.firstChildElement("description").text()); - field.setRequired(!fieldElement.firstChildElement("required").isNull()); - - m_fields.append(field); - - fieldElement = fieldElement.nextSiblingElement("field"); - } -} - -void QXmppDataForm::toXml(QXmlStreamWriter *writer) const -{ - if (isNull()) - return; - - writer->writeStartElement("x"); - writer->writeAttribute("xmlns", ns_data); - - /* form type */ - QString typeStr; - if (m_type == QXmppDataForm::Form) - typeStr = "form"; - else if (m_type == QXmppDataForm::Submit) - typeStr = "submit"; - else if (m_type == QXmppDataForm::Cancel) - typeStr = "cancel"; - else if (m_type == QXmppDataForm::Result) - typeStr = "result"; - helperToXmlAddAttribute(writer, "type", typeStr); - - /* form properties */ - if (!m_title.isEmpty()) - helperToXmlAddTextElement(writer, "title", m_title); - if (!m_instructions.isEmpty()) - helperToXmlAddTextElement(writer, "instructions", m_instructions); - - - foreach (const QXmppDataForm::Field &field, m_fields) - { - writer->writeStartElement("field"); - - /* field type */ - const QXmppDataForm::Field::Type type = field.type(); - QString typeStr; - struct field_type *ptr; - for (ptr = field_types; ptr->str; ptr++) - { - if (type == ptr->type) - { - typeStr = ptr->str; - break; - } - } - helperToXmlAddAttribute(writer, "type", typeStr); - - /* field attributes */ - helperToXmlAddAttribute(writer, "label", field.label()); - helperToXmlAddAttribute(writer, "var", field.key()); - - /* field value(s) */ - if (type == QXmppDataForm::Field::BooleanField) - { - helperToXmlAddTextElement(writer, "value", field.value().toBool() ? "1" : "0"); - } - else if (type == QXmppDataForm::Field::ListMultiField || - type == QXmppDataForm::Field::JidMultiField || - type == QXmppDataForm::Field::TextMultiField) - { - foreach (const QString &value, field.value().toStringList()) - helperToXmlAddTextElement(writer, "value", value); - } - else - { - helperToXmlAddTextElement(writer, "value", field.value().toString()); - } - - /* field options */ - if (type == QXmppDataForm::Field::ListMultiField || - type == QXmppDataForm::Field::ListSingleField) - { - QPair option; - foreach (option, field.options()) - { - writer->writeStartElement("option"); - helperToXmlAddAttribute(writer, "label", option.first); - helperToXmlAddTextElement(writer, "value", option.second); - writer->writeEndElement(); - } - } - - /* other properties */ - if (!field.description().isEmpty()) - helperToXmlAddTextElement(writer, "description", field.description()); - if (field.isRequired()) - helperToXmlAddTextElement(writer, "required", ""); - - writer->writeEndElement(); - } - - writer->writeEndElement(); -} - diff --git a/src/QXmppDataForm.h b/src/QXmppDataForm.h deleted file mode 100644 index 4f38a932..00000000 --- a/src/QXmppDataForm.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPDATAFORM_H -#define QXMPPDATAFORM_H - -#include -#include -#include -#include - -class QDomElement; - -/// \brief The QXmppDataForm class represents a data form as defined by -/// XEP-0004: Data Forms. -/// - -class QXmppDataForm -{ -public: - /// \brief The QXmppDataForm::Field class represents a data form field - /// as defined by XEP-0004: Data Forms. - /// - - class Field - { - public: - /// This enum is used to describe a field's type. - enum Type - { - BooleanField, - FixedField, - HiddenField, - JidMultiField, - JidSingleField, - ListMultiField, - ListSingleField, - TextMultiField, - TextPrivateField, - TextSingleField, - }; - - Field(QXmppDataForm::Field::Type type = QXmppDataForm::Field::TextSingleField); - - QString description() const; - void setDescription(const QString &description); - - QString key() const; - void setKey(const QString &key); - - QString label() const; - void setLabel(const QString &label); - - QList > options() const; - void setOptions(const QList > &options); - - bool isRequired() const; - void setRequired(bool required); - - QXmppDataForm::Field::Type type() const; - void setType(QXmppDataForm::Field::Type type); - - QVariant value() const; - void setValue(const QVariant &value); - - private: - QString m_description; - QString m_key; - QString m_label; - QList > m_options; - bool m_required; - QXmppDataForm::Field::Type m_type; - QVariant m_value; - }; - - /// This enum is used to describe a form's type. - enum Type - { - None, ///< Unknown form type - Form, ///< The form-processing entity is asking the form-submitting - ///< entity to complete a form. - Submit, ///< The form-submitting entity is submitting data to the - ///< form-processing entity. - Cancel, ///< The form-submitting entity has cancelled submission - ///< of data to the form-processing entity. - Result, ///< The form-processing entity is returning data - ///< (e.g., search results) to the form-submitting entity, - ///< or the data is a generic data set. - }; - - QXmppDataForm(QXmppDataForm::Type type = QXmppDataForm::None); - - QString instructions() const; - void setInstructions(const QString &instructions); - - QList fields() const; - QList &fields(); - void setFields(const QList &fields); - - QString title() const; - void setTitle(const QString &title); - - QXmppDataForm::Type type() const; - void setType(QXmppDataForm::Type type); - - bool isNull() const; - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString m_instructions; - QList m_fields; - QString m_title; - QXmppDataForm::Type m_type; -}; - -#endif diff --git a/src/QXmppDiscoveryIq.cpp b/src/QXmppDiscoveryIq.cpp deleted file mode 100644 index 6e0d33d5..00000000 --- a/src/QXmppDiscoveryIq.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include -#include - -#include "QXmppConstants.h" -#include "QXmppDiscoveryIq.h" -#include "QXmppUtils.h" - -static bool identityLessThan(const QXmppDiscoveryIq::Identity &i1, const QXmppDiscoveryIq::Identity &i2) -{ - if (i1.category() < i2.category()) - return true; - else if (i1.category() > i2.category()) - return false; - - if (i1.type() < i2.type()) - return true; - else if (i1.type() > i2.type()) - return false; - - if (i1.language() < i2.language()) - return true; - else if (i1.language() > i2.language()) - return false; - - if (i1.name() < i2.name()) - return true; - else if (i1.name() > i2.name()) - return false; - - return false; -} - -QString QXmppDiscoveryIq::Identity::category() const -{ - return m_category; -} - -void QXmppDiscoveryIq::Identity::setCategory(const QString &category) -{ - m_category = category; -} - -QString QXmppDiscoveryIq::Identity::language() const -{ - return m_language; -} - -void QXmppDiscoveryIq::Identity::setLanguage(const QString &language) -{ - m_language = language; -} - -QString QXmppDiscoveryIq::Identity::name() const -{ - return m_name; -} - -void QXmppDiscoveryIq::Identity::setName(const QString &name) -{ - m_name = name; -} - -QString QXmppDiscoveryIq::Identity::type() const -{ - return m_type; -} - -void QXmppDiscoveryIq::Identity::setType(const QString &type) -{ - m_type = type; -} - -QString QXmppDiscoveryIq::Item::jid() const -{ - return m_jid; -} - -void QXmppDiscoveryIq::Item::setJid(const QString &jid) -{ - m_jid = jid; -} - -QString QXmppDiscoveryIq::Item::name() const -{ - return m_name; -} - -void QXmppDiscoveryIq::Item::setName(const QString &name) -{ - m_name = name; -} - -QString QXmppDiscoveryIq::Item::node() const -{ - return m_node; -} - -void QXmppDiscoveryIq::Item::setNode(const QString &node) -{ - m_node = node; -} - -QStringList QXmppDiscoveryIq::features() const -{ - return m_features; -} - -void QXmppDiscoveryIq::setFeatures(const QStringList &features) -{ - m_features = features; -} - -QList QXmppDiscoveryIq::identities() const -{ - return m_identities; -} - -void QXmppDiscoveryIq::setIdentities(const QList &identities) -{ - m_identities = identities; -} - -QList QXmppDiscoveryIq::items() const -{ - return m_items; -} - -void QXmppDiscoveryIq::setItems(const QList &items) -{ - m_items = items; -} - -/// Returns the QXmppDataForm for this IQ, as defined by -/// XEP-0128: Service Discovery Extensions. -/// - -QXmppDataForm QXmppDiscoveryIq::form() const -{ - return m_form; -} - -/// Sets the QXmppDataForm for this IQ, as define by -/// XEP-0128: Service Discovery Extensions. -/// -/// \param form -/// - -void QXmppDiscoveryIq::setForm(const QXmppDataForm &form) -{ - m_form = form; -} - -QString QXmppDiscoveryIq::queryNode() const -{ - return m_queryNode; -} - -void QXmppDiscoveryIq::setQueryNode(const QString &node) -{ - m_queryNode = node; -} - -enum QXmppDiscoveryIq::QueryType QXmppDiscoveryIq::queryType() const -{ - return m_queryType; -} - -void QXmppDiscoveryIq::setQueryType(enum QXmppDiscoveryIq::QueryType type) -{ - m_queryType = type; -} - -/// Calculate the verification string for XEP-0115 : Entity Capabilities - -QByteArray QXmppDiscoveryIq::verificationString() const -{ - QString S; - QList sortedIdentities = m_identities; - qSort(sortedIdentities.begin(), sortedIdentities.end(), identityLessThan); - QStringList sortedFeatures = m_features; - qSort(sortedFeatures); - foreach (const QXmppDiscoveryIq::Identity &identity, sortedIdentities) - S += QString("%1/%2/%3/%4<").arg(identity.category(), identity.type(), identity.language(), identity.name()); - foreach (const QString &feature, sortedFeatures) - S += feature + QLatin1String("<"); - QCryptographicHash hasher(QCryptographicHash::Sha1); - hasher.addData(S.toUtf8()); - return hasher.result(); -} - -bool QXmppDiscoveryIq::isDiscoveryIq(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - return (queryElement.namespaceURI() == ns_disco_info || - queryElement.namespaceURI() == ns_disco_items); -} - -void QXmppDiscoveryIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - m_queryNode = queryElement.attribute("node"); - if (queryElement.namespaceURI() == ns_disco_items) - m_queryType = ItemsQuery; - else - m_queryType = InfoQuery; - - QDomElement itemElement = queryElement.firstChildElement(); - while (!itemElement.isNull()) - { - if (itemElement.tagName() == "feature") - { - m_features.append(itemElement.attribute("var")); - } - else if (itemElement.tagName() == "identity") - { - QXmppDiscoveryIq::Identity identity; - identity.setLanguage(itemElement.attribute("xml:lang")); - identity.setCategory(itemElement.attribute("category")); - identity.setName(itemElement.attribute("name")); - identity.setType(itemElement.attribute("type")); - m_identities.append(identity); - } - else if (itemElement.tagName() == "item") - { - QXmppDiscoveryIq::Item item; - item.setJid(itemElement.attribute("jid")); - item.setName(itemElement.attribute("name")); - item.setNode(itemElement.attribute("node")); - m_items.append(item); - } - else if (itemElement.tagName() == "x" && - itemElement.namespaceURI() == ns_data) - { - m_form.parse(itemElement); - } - itemElement = itemElement.nextSiblingElement(); - } -} - -void QXmppDiscoveryIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("query"); - writer->writeAttribute("xmlns", - m_queryType == InfoQuery ? ns_disco_info : ns_disco_items); - helperToXmlAddAttribute(writer, "node", m_queryNode); - - foreach (const QString &feature, m_features) - { - writer->writeStartElement("feature"); - helperToXmlAddAttribute(writer, "var", feature); - writer->writeEndElement(); - } - - foreach (const QXmppDiscoveryIq::Identity& identity, m_identities) - { - writer->writeStartElement("identity"); - helperToXmlAddAttribute(writer, "xml:lang", identity.language()); - helperToXmlAddAttribute(writer, "category", identity.category()); - helperToXmlAddAttribute(writer, "name", identity.name()); - helperToXmlAddAttribute(writer, "type", identity.type()); - writer->writeEndElement(); - } - - foreach (const QXmppDiscoveryIq::Item& item, m_items) - { - writer->writeStartElement("item"); - helperToXmlAddAttribute(writer, "jid", item.jid()); - helperToXmlAddAttribute(writer, "name", item.name()); - helperToXmlAddAttribute(writer, "node", item.node()); - writer->writeEndElement(); - } - - m_form.toXml(writer); - - writer->writeEndElement(); -} - diff --git a/src/QXmppDiscoveryIq.h b/src/QXmppDiscoveryIq.h deleted file mode 100644 index 40aa1a3b..00000000 --- a/src/QXmppDiscoveryIq.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPDISCOVERY_H -#define QXMPPDISCOVERY_H - -#include "QXmppDataForm.h" -#include "QXmppIq.h" - -class QDomElement; - -class QXmppDiscoveryIq : public QXmppIq -{ -public: - class Identity - { - public: - QString category() const; - void setCategory(const QString &category); - - QString language() const; - void setLanguage(const QString &language); - - QString name() const; - void setName(const QString &name); - - QString type() const; - void setType(const QString &type); - - private: - QString m_category; - QString m_language; - QString m_name; - QString m_type; - }; - - class Item - { - public: - QString jid() const; - void setJid(const QString &jid); - - QString name() const; - void setName(const QString &name); - - QString node() const; - void setNode(const QString &node); - - private: - QString m_jid; - QString m_name; - QString m_node; - }; - - enum QueryType { - InfoQuery, - ItemsQuery, - }; - - QStringList features() const; - void setFeatures(const QStringList &features); - - QList identities() const; - void setIdentities(const QList &identities); - - QList items() const; - void setItems(const QList &items); - - QXmppDataForm form() const; - void setForm(const QXmppDataForm &form); - - QString queryNode() const; - void setQueryNode(const QString &node); - - enum QueryType queryType() const; - void setQueryType(enum QueryType type); - - QByteArray verificationString() const; - - static bool isDiscoveryIq(const QDomElement &element); - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QStringList m_features; - QList m_identities; - QList m_items; - QXmppDataForm m_form; - QString m_queryNode; - enum QueryType m_queryType; -}; - -#endif diff --git a/src/QXmppElement.cpp b/src/QXmppElement.cpp deleted file mode 100644 index 904ab473..00000000 --- a/src/QXmppElement.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include "QXmppElement.h" -#include "QXmppUtils.h" - -#include - -class QXmppElementPrivate -{ -public: - QXmppElementPrivate(); - QXmppElementPrivate(const QDomElement &element); - ~QXmppElementPrivate(); - - QAtomicInt counter; - - QXmppElementPrivate *parent; - QMap attributes; - QList children; - QString name; - QString value; -}; - -QXmppElementPrivate::QXmppElementPrivate() - : counter(1), parent(NULL) -{ -} - -QXmppElementPrivate::QXmppElementPrivate(const QDomElement &element) - : counter(1), parent(NULL) -{ - if (element.isNull()) - return; - - name = element.tagName(); - QString xmlns = element.namespaceURI(); - QString parentns = element.parentNode().namespaceURI(); - if (!xmlns.isEmpty() && xmlns != parentns) - attributes.insert("xmlns", xmlns); - QDomNamedNodeMap attrs = element.attributes(); - for (int i = 0; i < attrs.size(); i++) - { - QDomAttr attr = attrs.item(i).toAttr(); - attributes.insert(attr.name(), attr.value()); - } - - QDomNode childNode = element.firstChild(); - while (!childNode.isNull()) - { - if (childNode.isElement()) - { - QXmppElementPrivate *child = new QXmppElementPrivate(childNode.toElement()); - child->parent = this; - children.append(child); - } else if (childNode.isText()) { - value += childNode.toText().data(); - } - childNode = childNode.nextSibling(); - } -} - -QXmppElementPrivate::~QXmppElementPrivate() -{ - foreach (QXmppElementPrivate *child, children) - if (!child->counter.deref()) - delete child; -} - -QXmppElement::QXmppElement() -{ - d = new QXmppElementPrivate(); -} - -QXmppElement::QXmppElement(const QXmppElement &other) -{ - other.d->counter.ref(); - d = other.d; -} - -QXmppElement::QXmppElement(QXmppElementPrivate *other) -{ - other->counter.ref(); - d = other; -} - -QXmppElement::QXmppElement(const QDomElement &element) -{ - d = new QXmppElementPrivate(element); -} - -QXmppElement::~QXmppElement() -{ - if (!d->counter.deref()) - delete d; -} - -QXmppElement &QXmppElement::operator=(const QXmppElement &other) -{ - other.d->counter.ref(); - if (!d->counter.deref()) - delete d; - d = other.d; - return *this; -} - -QStringList QXmppElement::attributeNames() const -{ - return d->attributes.keys(); -} - -QString QXmppElement::attribute(const QString &name) const -{ - return d->attributes.value(name); -} - -void QXmppElement::setAttribute(const QString &name, const QString &value) -{ - d->attributes.insert(name, value); -} - -void QXmppElement::appendChild(const QXmppElement &child) -{ - if (child.d->parent == d) - return; - - if (child.d->parent) - child.d->parent->children.removeAll(child.d); - else - child.d->counter.ref(); - child.d->parent = d; - d->children.append(child.d); -} - -QXmppElement QXmppElement::firstChildElement(const QString &name) const -{ - foreach (QXmppElementPrivate *child_d, d->children) - if (name.isEmpty() || child_d->name == name) - return QXmppElement(child_d); - return QXmppElement(); -} - -QXmppElement QXmppElement::nextSiblingElement(const QString &name) const -{ - if (!d->parent) - return QXmppElement(); - const QList &siblings_d = d->parent->children; - for (int i = siblings_d.indexOf(d) + 1; i < siblings_d.size(); i++) - if (name.isEmpty() || siblings_d[i]->name == name) - return QXmppElement(siblings_d[i]); - return QXmppElement(); -} - -bool QXmppElement::isNull() const -{ - return d->name.isEmpty(); -} - -void QXmppElement::removeChild(const QXmppElement &child) -{ - if (child.d->parent != d) - return; - - d->children.removeAll(child.d); - child.d->counter.deref(); - child.d->parent = NULL; -} - -QString QXmppElement::tagName() const -{ - return d->name; -} - -void QXmppElement::setTagName(const QString &tagName) -{ - d->name = tagName; -} - -QString QXmppElement::value() const -{ - return d->value; -} - -void QXmppElement::setValue(const QString &value) -{ - d->value = value; -} - -void QXmppElement::toXml(QXmlStreamWriter *writer) const -{ - if (isNull()) - return; - - writer->writeStartElement(d->name); - if (d->attributes.contains("xmlns")) - writer->writeAttribute("xmlns", d->attributes.value("xmlns")); - foreach (const QString &attr, d->attributes.keys()) - if (attr != "xmlns") - helperToXmlAddAttribute(writer, attr, d->attributes.value(attr)); - if (!d->value.isEmpty()) - writer->writeCharacters(d->value); - foreach (const QXmppElement &child, d->children) - child.toXml(writer); - writer->writeEndElement(); -} - -QXmppElementList::QXmppElementList() -{ -} - -QXmppElementList::QXmppElementList(const QXmppElement &element) -{ - append(element); -} - - -QXmppElementList::QXmppElementList(const QList &other) - : QList(other) -{ -} - diff --git a/src/QXmppElement.h b/src/QXmppElement.h deleted file mode 100644 index 7fa75494..00000000 --- a/src/QXmppElement.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPELEMENT_H -#define QXMPPELEMENT_H - -#include -#include -#include - -class QDomElement; -class QXmppElement; -class QXmppElementPrivate; - -class QXmppElementList : public QList -{ -public: - QXmppElementList(); - QXmppElementList(const QXmppElement &element); - QXmppElementList(const QList &other); -}; - -class QXmppElement -{ -public: - QXmppElement(); - QXmppElement(const QXmppElement &other); - QXmppElement(const QDomElement &element); - ~QXmppElement(); - - QStringList attributeNames() const; - - QString attribute(const QString &name) const; - void setAttribute(const QString &name, const QString &value); - - void appendChild(const QXmppElement &child); - QXmppElement firstChildElement(const QString &name = QString()) const; - QXmppElement nextSiblingElement(const QString &name = QString()) const; - void removeChild(const QXmppElement &child); - - QString tagName() const; - void setTagName(const QString &type); - - QString value() const; - void setValue(const QString &text); - - bool isNull() const; - void toXml(QXmlStreamWriter *writer) const; - - QXmppElement &operator=(const QXmppElement &other); - -private: - QXmppElement(QXmppElementPrivate *other); - QXmppElementPrivate *d; -}; - -#endif diff --git a/src/QXmppEntityTimeIq.cpp b/src/QXmppEntityTimeIq.cpp deleted file mode 100644 index 5e41e39f..00000000 --- a/src/QXmppEntityTimeIq.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#include "QXmppEntityTimeIq.h" - -#include - -#include "QXmppConstants.h" -#include "QXmppUtils.h" - -/// Returns the timezone offset in seconds. -/// - -int QXmppEntityTimeIq::tzo() const -{ - return m_tzo; -} - -/// Sets the timezone offset in seconds. -/// -/// \param tzo - -void QXmppEntityTimeIq::setTzo(int tzo) -{ - m_tzo = tzo; -} - -/// Returns the date/time in Coordinated Universal Time (UTC). -/// - -QDateTime QXmppEntityTimeIq::utc() const -{ - return m_utc; -} - -/// Sets the date/time in Coordinated Universal Time (UTC). -/// -/// \param utc - -void QXmppEntityTimeIq::setUtc(const QDateTime &utc) -{ - m_utc = utc; -} - -bool QXmppEntityTimeIq::isEntityTimeIq(const QDomElement &element) -{ - QDomElement timeElement = element.firstChildElement("time"); - return timeElement.namespaceURI() == ns_entity_time; -} - -void QXmppEntityTimeIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement timeElement = element.firstChildElement("time"); - m_tzo = timezoneOffsetFromString(timeElement.firstChildElement("tzo").text()); - m_utc = datetimeFromString(timeElement.firstChildElement("utc").text()); -} - -void QXmppEntityTimeIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("time"); - writer->writeAttribute("xmlns", ns_entity_time); - - if(m_utc.isValid()) - { - helperToXmlAddTextElement(writer, "tzo", timezoneOffsetToString(m_tzo)); - helperToXmlAddTextElement(writer, "utc", datetimeToString(m_utc)); - } - writer->writeEndElement(); -} diff --git a/src/QXmppEntityTimeIq.h b/src/QXmppEntityTimeIq.h deleted file mode 100644 index fa3d5f12..00000000 --- a/src/QXmppEntityTimeIq.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPENTITYTIMEIQ_H -#define QXMPPENTITYTIMEIQ_H - -#include - -#include "QXmppIq.h" - -/// \ingroup Stanzas - -class QXmppEntityTimeIq : public QXmppIq -{ -public: - int tzo() const; - void setTzo(int tzo); - - QDateTime utc() const; - void setUtc(const QDateTime &utc); - - static bool isEntityTimeIq(const QDomElement &element); - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - int m_tzo; - QDateTime m_utc; -}; - -#endif //QXMPPENTITYTIMEIQ_H diff --git a/src/QXmppGlobal.cpp b/src/QXmppGlobal.cpp deleted file mode 100644 index 2735788a..00000000 --- a/src/QXmppGlobal.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#include "QXmppGlobal.h" - -QString QXmppVersion() -{ - return QString("%1.%2.%3").arg( - QString::number((QXMPP_VERSION >> 16) & 0xff), - QString::number((QXMPP_VERSION >> 8) & 0xff), - QString::number(QXMPP_VERSION & 0xff)); -} - diff --git a/src/QXmppGlobal.h b/src/QXmppGlobal.h deleted file mode 100644 index 36122d1a..00000000 --- a/src/QXmppGlobal.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPGLOBAL_H -#define QXMPPGLOBAL_H - -#include - -/// This macro expands a numeric value of the form 0xMMNNPP (MM = -/// major, NN = minor, PP = patch) that specifies QXmpp's version -/// number. For example, if you compile your application against -/// QXmpp 1.2.3, the QXMPP_VERSION macro will expand to 0x010203. -/// -/// You can use QXMPP_VERSION to use the latest QXmpp features where -/// available. -/// - -#define QXMPP_VERSION 0x00035b - -QString QXmppVersion(); - -#endif //QXMPPGLOBAL_H diff --git a/src/QXmppIbbIq.cpp b/src/QXmppIbbIq.cpp deleted file mode 100644 index 85aba54a..00000000 --- a/src/QXmppIbbIq.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include -#include - -#include "QXmppConstants.h" -#include "QXmppIbbIq.h" - -QXmppIbbOpenIq::QXmppIbbOpenIq() : QXmppIq(QXmppIq::Set), m_block_size(1024) -{ - -} - -long QXmppIbbOpenIq::blockSize() const -{ - return m_block_size; -} - -void QXmppIbbOpenIq::setBlockSize( long block_size ) -{ - m_block_size = block_size; -} - -QString QXmppIbbOpenIq::sid() const -{ - return m_sid; -} - -void QXmppIbbOpenIq::setSid( const QString &sid ) -{ - m_sid = sid; -} - -bool QXmppIbbOpenIq::isIbbOpenIq(const QDomElement &element) -{ - QDomElement openElement = element.firstChildElement("open"); - return openElement.namespaceURI() == ns_ibb; -} - -void QXmppIbbOpenIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement openElement = element.firstChildElement("open"); - m_sid = openElement.attribute( "sid" ); - m_block_size = openElement.attribute( "block-size" ).toLong(); -} - -void QXmppIbbOpenIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("open"); - writer->writeAttribute( "xmlns",ns_ibb); - writer->writeAttribute( "sid",m_sid); - writer->writeAttribute( "block-size",QString::number(m_block_size) ); - writer->writeEndElement(); -} - -QXmppIbbCloseIq::QXmppIbbCloseIq() : QXmppIq(QXmppIq::Set) -{ - -} - -QString QXmppIbbCloseIq::sid() const -{ - return m_sid; -} - -void QXmppIbbCloseIq::setSid( const QString &sid ) -{ - m_sid = sid; -} - -bool QXmppIbbCloseIq::isIbbCloseIq(const QDomElement &element) -{ - QDomElement openElement = element.firstChildElement("close"); - return openElement.namespaceURI() == ns_ibb; -} - -void QXmppIbbCloseIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement openElement = element.firstChildElement("close"); - m_sid = openElement.attribute( "sid" ); -} - -void QXmppIbbCloseIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("close"); - writer->writeAttribute( "xmlns",ns_ibb); - writer->writeAttribute( "sid",m_sid); - writer->writeEndElement(); -} - -QXmppIbbDataIq::QXmppIbbDataIq() : QXmppIq( QXmppIq::Set ), m_seq(0) -{ -} - -quint16 QXmppIbbDataIq::sequence() const -{ - return m_seq; -} - -void QXmppIbbDataIq::setSequence( quint16 seq ) -{ - m_seq = seq; -} - -QString QXmppIbbDataIq::sid() const -{ - return m_sid; -} - -void QXmppIbbDataIq::setSid( const QString &sid ) -{ - m_sid = sid; -} - -QByteArray QXmppIbbDataIq::payload() const -{ - return m_payload; -} - -void QXmppIbbDataIq::setPayload( const QByteArray &data ) -{ - m_payload = data; -} - -bool QXmppIbbDataIq::isIbbDataIq(const QDomElement &element) -{ - QDomElement dataElement = element.firstChildElement("data"); - return dataElement.namespaceURI() == ns_ibb; -} - -void QXmppIbbDataIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement dataElement = element.firstChildElement("data"); - m_sid = dataElement.attribute( "sid" ); - m_seq = dataElement.attribute( "seq" ).toLong(); - m_payload = QByteArray::fromBase64( dataElement.text().toLatin1() ); -} - -void QXmppIbbDataIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("data"); - writer->writeAttribute( "xmlns",ns_ibb); - writer->writeAttribute( "sid",m_sid); - writer->writeAttribute( "seq",QString::number(m_seq) ); - writer->writeCharacters( m_payload.toBase64() ); - writer->writeEndElement(); -} diff --git a/src/QXmppIbbIq.h b/src/QXmppIbbIq.h deleted file mode 100644 index 592b12f4..00000000 --- a/src/QXmppIbbIq.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPIBBIQ_H -#define QXMPPIBBIQ_H - -#include "QXmppIq.h" - -class QDomElement; -class QXmlStreamWriter; - -class QXmppIbbOpenIq: public QXmppIq -{ -public: - QXmppIbbOpenIq(); - - long blockSize() const; - void setBlockSize( long block_size ); - - QString sid() const; - void setSid( const QString &sid ); - - static bool isIbbOpenIq(const QDomElement &element); - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - long m_block_size; - QString m_sid; -}; - -class QXmppIbbCloseIq: public QXmppIq -{ -public: - QXmppIbbCloseIq(); - - QString sid() const; - void setSid( const QString &sid ); - - static bool isIbbCloseIq(const QDomElement &element); - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString m_sid; -}; - -class QXmppIbbDataIq : public QXmppIq -{ -public: - QXmppIbbDataIq(); - - quint16 sequence() const; - void setSequence( quint16 seq ); - - QString sid() const; - void setSid( const QString &sid ); - - QByteArray payload() const; - void setPayload( const QByteArray &data ); - - static bool isIbbDataIq(const QDomElement &element); - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - quint16 m_seq; - QString m_sid; - QByteArray m_payload; -}; - -#endif // QXMPPIBBIQS_H diff --git a/src/QXmppIq.cpp b/src/QXmppIq.cpp deleted file mode 100644 index d0ee0a7a..00000000 --- a/src/QXmppIq.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#include "QXmppUtils.h" -#include "QXmppIq.h" - -#include -#include - -/// Constructs a QXmppIq with the specified \a type. -/// -/// \param type - -QXmppIq::QXmppIq(QXmppIq::Type type) - : QXmppStanza(), m_type(type) -{ - generateAndSetNextId(); -} - -/// Returns the IQ's type. -/// - -QXmppIq::Type QXmppIq::type() const -{ - return m_type; -} - -/// Sets the IQ's type. -/// -/// \param type - -void QXmppIq::setType(QXmppIq::Type type) -{ - m_type = type; -} - -void QXmppIq::parse(const QDomElement &element) -{ - QXmppStanza::parse(element); - setTypeFromStr(element.attribute("type")); - parseElementFromChild(element); -} - -void QXmppIq::parseElementFromChild(const QDomElement &element) -{ - QXmppElementList extensions; - QDomElement itemElement = element.firstChildElement(); - while (!itemElement.isNull()) - { - extensions.append(QXmppElement(itemElement)); - itemElement = itemElement.nextSiblingElement(); - } - setExtensions(extensions); -} - -void QXmppIq::toXml( QXmlStreamWriter *xmlWriter ) const -{ - xmlWriter->writeStartElement("iq"); - - helperToXmlAddAttribute(xmlWriter, "id", id()); - helperToXmlAddAttribute(xmlWriter, "to", to()); - helperToXmlAddAttribute(xmlWriter, "from", from()); - if(getTypeStr().isEmpty()) - helperToXmlAddAttribute(xmlWriter, "type", "get"); - else - helperToXmlAddAttribute(xmlWriter, "type", getTypeStr()); - toXmlElementFromChild(xmlWriter); - error().toXml(xmlWriter); - xmlWriter->writeEndElement(); -} - -void QXmppIq::toXmlElementFromChild( QXmlStreamWriter *writer ) const -{ - foreach (const QXmppElement &extension, extensions()) - extension.toXml(writer); -} - -QString QXmppIq::getTypeStr() const -{ - switch(m_type) - { - case QXmppIq::Error: - return "error"; - case QXmppIq::Get: - return "get"; - case QXmppIq::Set: - return "set"; - case QXmppIq::Result: - return "result"; - default: - qWarning("QXmppIq::getTypeStr() invalid type %d", (int)m_type); - return ""; - } -} - -void QXmppIq::setTypeFromStr(const QString& str) -{ - if(str == "error") - { - setType(QXmppIq::Error); - return; - } - else if(str == "get") - { - setType(QXmppIq::Get); - return; - } - else if(str == "set") - { - setType(QXmppIq::Set); - return; - } - else if(str == "result") - { - setType(QXmppIq::Result); - return; - } - else - { - setType(static_cast(-1)); - qWarning("QXmppIq::setTypeFromStr() invalid input string type: %s", - qPrintable(str)); - return; - } -} - diff --git a/src/QXmppIq.h b/src/QXmppIq.h deleted file mode 100644 index bbde3d06..00000000 --- a/src/QXmppIq.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPIQ_H -#define QXMPPIQ_H - -#include "QXmppStanza.h" - -// forward declarations of QXmlStream* classes will not work on Mac, we need to -// include the whole header. -// See http://lists.trolltech.com/qt-interest/2008-07/thread00798-0.html -// for an explanation. -#include - -/// \brief The QXmppIq class is the base class for all IQs. -/// -/// \ingroup Stanzas - -class QXmppIq : public QXmppStanza -{ -public: - /// This enum describes the type of IQ. - enum Type - { - Error = 0, ///< Error response. - Get, ///< Get request. - Set, ///< Set request. - Result ///< Result. - }; - - QXmppIq(QXmppIq::Type type = QXmppIq::Get); - - QXmppIq::Type type() const; - void setType(QXmppIq::Type); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - -protected: - virtual void parseElementFromChild(const QDomElement &element); - virtual void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString getTypeStr() const; - void setTypeFromStr(const QString& str); - - Type m_type; -}; - -#endif // QXMPPIQ_H diff --git a/src/QXmppJingleIq.cpp b/src/QXmppJingleIq.cpp deleted file mode 100644 index 5eb11322..00000000 --- a/src/QXmppJingleIq.cpp +++ /dev/null @@ -1,848 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include "QXmppConstants.h" -#include "QXmppJingleIq.h" -#include "QXmppUtils.h" - -static const char* ns_jingle_rtp_info = "urn:xmpp:jingle:apps:rtp:info:1"; - -static const char* jingle_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* jingle_reasons[] = { - "", - "alternative-session", - "busy", - "cancel", - "connectivity-error", - "decline", - "expired", - "failed-application", - "failed-transport", - "general-error", - "gone", - "incompatible-parameters", - "media-error", - "security-error", - "success", - "timeout", - "unsupported-applications", - "unsupported-transports", -}; - -QXmppJingleIq::Content::Content() -{ -} - -QString QXmppJingleIq::Content::creator() const -{ - return m_creator; -} - -void QXmppJingleIq::Content::setCreator(const QString &creator) -{ - m_creator = creator; -} - -QString QXmppJingleIq::Content::name() const -{ - return m_name; -} - -void QXmppJingleIq::Content::setName(const QString &name) -{ - m_name = name; -} - -QString QXmppJingleIq::Content::senders() const -{ - return m_senders; -} - -void QXmppJingleIq::Content::setSenders(const QString &senders) -{ - m_senders = senders; -} - -QString QXmppJingleIq::Content::descriptionMedia() const -{ - return m_descriptionMedia; -} - -void QXmppJingleIq::Content::setDescriptionMedia(const QString &media) -{ - m_descriptionMedia = media; -} - -void QXmppJingleIq::Content::addPayloadType(const QXmppJinglePayloadType &payload) -{ - m_descriptionType = ns_jingle_rtp; - m_payloadTypes << payload; -} - -QList QXmppJingleIq::Content::payloadTypes() const -{ - return m_payloadTypes; -} - -void QXmppJingleIq::Content::setPayloadTypes(const QList &payloadTypes) -{ - m_descriptionType = payloadTypes.isEmpty() ? QString() : ns_jingle_rtp; - m_payloadTypes = payloadTypes; -} - -void QXmppJingleIq::Content::addTransportCandidate(const QXmppJingleCandidate &candidate) -{ - m_transportType = ns_jingle_ice_udp; - m_transportCandidates << candidate; -} - -QList QXmppJingleIq::Content::transportCandidates() const -{ - return m_transportCandidates; -} - -QString QXmppJingleIq::Content::transportUser() const -{ - return m_transportUser; -} - -void QXmppJingleIq::Content::setTransportUser(const QString &user) -{ - m_transportUser = user; -} - -QString QXmppJingleIq::Content::transportPassword() const -{ - return m_transportPassword; -} - -void QXmppJingleIq::Content::setTransportPassword(const QString &password) -{ - m_transportPassword = password; -} - -void QXmppJingleIq::Content::parse(const QDomElement &element) -{ - m_creator = element.attribute("creator"); - m_disposition = element.attribute("disposition"); - m_name = element.attribute("name"); - m_senders = element.attribute("senders"); - - // description - QDomElement descriptionElement = element.firstChildElement("description"); - m_descriptionType = descriptionElement.namespaceURI(); - m_descriptionMedia = descriptionElement.attribute("media"); - QDomElement child = descriptionElement.firstChildElement("payload-type"); - while (!child.isNull()) - { - QXmppJinglePayloadType payload; - payload.parse(child); - m_payloadTypes << payload; - child = child.nextSiblingElement("payload-type"); - } - - // transport - QDomElement transportElement = element.firstChildElement("transport"); - m_transportType = transportElement.namespaceURI(); - m_transportUser = transportElement.attribute("ufrag"); - m_transportPassword = transportElement.attribute("pwd"); - child = transportElement.firstChildElement("candidate"); - while (!child.isNull()) - { - QXmppJingleCandidate candidate; - candidate.parse(child); - m_transportCandidates << candidate; - child = child.nextSiblingElement("candidate"); - } -} - -void QXmppJingleIq::Content::toXml(QXmlStreamWriter *writer) const -{ - if (m_creator.isEmpty() || m_name.isEmpty()) - return; - - writer->writeStartElement("content"); - helperToXmlAddAttribute(writer, "creator", m_creator); - helperToXmlAddAttribute(writer, "disposition", m_disposition); - helperToXmlAddAttribute(writer, "name", m_name); - helperToXmlAddAttribute(writer, "senders", m_senders); - - // description - if (!m_descriptionType.isEmpty() || !m_payloadTypes.isEmpty()) - { - writer->writeStartElement("description"); - writer->writeAttribute("xmlns", m_descriptionType); - helperToXmlAddAttribute(writer, "media", m_descriptionMedia); - foreach (const QXmppJinglePayloadType &payload, m_payloadTypes) - payload.toXml(writer); - writer->writeEndElement(); - } - - // transport - if (!m_transportType.isEmpty() || !m_transportCandidates.isEmpty()) - { - writer->writeStartElement("transport"); - writer->writeAttribute("xmlns", m_transportType); - helperToXmlAddAttribute(writer, "ufrag", m_transportUser); - helperToXmlAddAttribute(writer, "pwd", m_transportPassword); - foreach (const QXmppJingleCandidate &candidate, m_transportCandidates) - candidate.toXml(writer); - writer->writeEndElement(); - } - writer->writeEndElement(); -} - -QXmppJingleIq::Reason::Reason() - : m_type(None) -{ -} - -QString QXmppJingleIq::Reason::text() const -{ - return m_text; -} - -void QXmppJingleIq::Reason::setText(const QString &text) -{ - m_text = text; -} - -QXmppJingleIq::Reason::Type QXmppJingleIq::Reason::type() const -{ - return m_type; -} - -void QXmppJingleIq::Reason::setType(QXmppJingleIq::Reason::Type type) -{ - m_type = type; -} - -void QXmppJingleIq::Reason::parse(const QDomElement &element) -{ - m_text = element.firstChildElement("text").text(); - for (int i = AlternativeSession; i <= UnsupportedTransports; i++) - { - if (!element.firstChildElement(jingle_reasons[i]).isNull()) - { - m_type = static_cast(i); - break; - } - } -} - -void QXmppJingleIq::Reason::toXml(QXmlStreamWriter *writer) const -{ - if (m_type < AlternativeSession || m_type > UnsupportedTransports) - return; - - writer->writeStartElement("reason"); - if (!m_text.isEmpty()) - helperToXmlAddTextElement(writer, "text", m_text); - writer->writeEmptyElement(jingle_reasons[m_type]); - writer->writeEndElement(); -} - -/// Constructs a QXmppJingleIq. - -QXmppJingleIq::QXmppJingleIq() - : m_ringing(false) -{ -} - -/// Returns the Jingle IQ's action. - -QXmppJingleIq::Action QXmppJingleIq::action() const -{ - return m_action; -} - -/// Sets the Jingle IQ's action. -/// -/// \param action - -void QXmppJingleIq::setAction(QXmppJingleIq::Action action) -{ - m_action = action; -} - -/// Returns the session initiator. - -QString QXmppJingleIq::initiator() const -{ - return m_initiator; -} - -/// Sets the session initiator. -/// -/// \param initiator - -void QXmppJingleIq::setInitiator(const QString &initiator) -{ - m_initiator = initiator; -} - -/// Returns the session responder. - -QString QXmppJingleIq::responder() const -{ - return m_responder; -} - -/// Sets the session responder. -/// -/// \param responder - -void QXmppJingleIq::setResponder(const QString &responder) -{ - m_responder = responder; -} - -/// Returns the session ID. - -QString QXmppJingleIq::sid() const -{ - return m_sid; -} - -/// Sets the session ID. -/// -/// \param sid - -void QXmppJingleIq::setSid(const QString &sid) -{ - m_sid = sid; -} - -bool QXmppJingleIq::isJingleIq(const QDomElement &element) -{ - QDomElement jingleElement = element.firstChildElement("jingle"); - return (jingleElement.namespaceURI() == ns_jingle); -} - -/// Returns true if the call is ringing. - -bool QXmppJingleIq::ringing() const -{ - return m_ringing; -} - -/// Set to true if the call is ringing. -/// -/// \param ringing - -void QXmppJingleIq::setRinging(bool ringing) -{ - m_ringing = ringing; -} - -void QXmppJingleIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement jingleElement = element.firstChildElement("jingle"); - const QString action = jingleElement.attribute("action"); - for (int i = ContentAccept; i <= TransportReplace; i++) - { - if (action == jingle_actions[i]) - { - m_action = static_cast(i); - break; - } - } - m_initiator = jingleElement.attribute("initiator"); - m_responder = jingleElement.attribute("responder"); - m_sid = jingleElement.attribute("sid"); - - // content - QDomElement contentElement = jingleElement.firstChildElement("content"); - m_content.parse(contentElement); - QDomElement reasonElement = jingleElement.firstChildElement("reason"); - m_reason.parse(reasonElement); - - // ringing - QDomElement ringingElement = jingleElement.firstChildElement("ringing"); - m_ringing = (ringingElement.namespaceURI() == ns_jingle_rtp_info); -} - -void QXmppJingleIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("jingle"); - writer->writeAttribute("xmlns", ns_jingle); - helperToXmlAddAttribute(writer, "action", jingle_actions[m_action]); - helperToXmlAddAttribute(writer, "initiator", m_initiator); - helperToXmlAddAttribute(writer, "responder", m_responder); - helperToXmlAddAttribute(writer, "sid", m_sid); - m_content.toXml(writer); - m_reason.toXml(writer); - - // ringing - if (m_ringing) - { - writer->writeStartElement("ringing"); - writer->writeAttribute("xmlns", ns_jingle_rtp_info); - writer->writeEndElement(); - } - - writer->writeEndElement(); -} - -QXmppJingleCandidate::QXmppJingleCandidate() - : m_component(0), - m_foundation(0), - m_generation(0), - m_network(0), - m_port(0), - m_priority(0), - m_type(HostType) -{ -} - -/// Returns the candidate's component ID. - -int QXmppJingleCandidate::component() const -{ - return m_component; -} - -/// Sets the candidates's component ID. -/// -/// \param component - -void QXmppJingleCandidate::setComponent(int component) -{ - m_component = component; -} - -/// Returns the candidate's foundation. - -int QXmppJingleCandidate::foundation() const -{ - return m_foundation; -} - -/// Sets the candidate's foundation. -/// -/// \param foundation - -void QXmppJingleCandidate::setFoundation(int foundation) -{ - m_foundation = foundation; -} - -/// Returns the candidate's host address. -/// - -QHostAddress QXmppJingleCandidate::host() const -{ - return m_host; -} - -/// Sets the candidate's host address. -/// -/// \param host - -void QXmppJingleCandidate::setHost(const QHostAddress &host) -{ - m_host = host; -} - -/// Returns the candidate's unique identifier. -/// - -QString QXmppJingleCandidate::id() const -{ - return m_id; -} - -/// Sets the candidate's unique identifier. -/// -/// \param id - -void QXmppJingleCandidate::setId(const QString &id) -{ - m_id = id; -} - -/// Returns the network index (starting at 0) the candidate is on. -/// - -int QXmppJingleCandidate::network() const -{ - return m_network; -} - -/// Sets the network index (starting at 0) the candidate is on. -/// -/// \param network - -void QXmppJingleCandidate::setNetwork(int network) -{ - m_network = network; -} - -/// Returns the candidate's port number. -/// - -quint16 QXmppJingleCandidate::port() const -{ - return m_port; -} - -/// Sets the candidate's port number. -/// -/// \param port - -void QXmppJingleCandidate::setPort(quint16 port) -{ - m_port = port; -} - -/// Returns the candidate's priority. -/// - -int QXmppJingleCandidate::priority() const -{ - return m_priority; -} - -/// Sets the candidate's priority. -/// -/// \param priority - -void QXmppJingleCandidate::setPriority(int priority) -{ - m_priority = priority; -} - -/// Returns the candidate's protocol (e.g. "udp"). -/// - -QString QXmppJingleCandidate::protocol() const -{ - return m_protocol; -} - -/// Sets the candidate's protocol (e.g. "udp"). -/// -/// \param protocol - -void QXmppJingleCandidate::setProtocol(const QString &protocol) -{ - m_protocol = protocol; -} - -/// Returns the candidate type (e.g. "host"). -/// - -QXmppJingleCandidate::Type QXmppJingleCandidate::type() const -{ - return m_type; -} - -/// Sets the candidate type (e.g. "host"). -/// -/// \param type - -void QXmppJingleCandidate::setType(QXmppJingleCandidate::Type type) -{ - m_type = type; -} - -/// Returns true if the host address or port are empty. -/// - -bool QXmppJingleCandidate::isNull() const -{ - return m_host.isNull() || !m_port; -} - -void QXmppJingleCandidate::parse(const QDomElement &element) -{ - m_component = element.attribute("component").toInt(); - m_foundation = element.attribute("foundation").toInt(); - m_generation = element.attribute("generation").toInt(); - m_host = QHostAddress(element.attribute("ip")); - m_id = element.attribute("id"); - m_network = element.attribute("network").toInt(); - m_port = element.attribute("port").toInt(); - m_priority = element.attribute("priority").toInt(); - m_protocol = element.attribute("protocol"); - m_type = typeFromString(element.attribute("type")); -} - -void QXmppJingleCandidate::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("candidate"); - helperToXmlAddAttribute(writer, "component", QString::number(m_component)); - helperToXmlAddAttribute(writer, "foundation", QString::number(m_foundation)); - helperToXmlAddAttribute(writer, "generation", QString::number(m_generation)); - helperToXmlAddAttribute(writer, "id", m_id); - helperToXmlAddAttribute(writer, "ip", m_host.toString()); - helperToXmlAddAttribute(writer, "network", QString::number(m_network)); - helperToXmlAddAttribute(writer, "port", QString::number(m_port)); - helperToXmlAddAttribute(writer, "priority", QString::number(m_priority)); - helperToXmlAddAttribute(writer, "protocol", m_protocol); - helperToXmlAddAttribute(writer, "type", typeToString(m_type)); - writer->writeEndElement(); -} - -QXmppJingleCandidate::Type QXmppJingleCandidate::typeFromString(const QString &typeStr, bool *ok) -{ - QXmppJingleCandidate::Type type; - if (typeStr == "host") - type = HostType; - else if (typeStr == "prflx") - type = PeerReflexiveType; - else if (typeStr == "srflx") - type = ServerReflexiveType; - else if (typeStr == "relay") - type = RelayedType; - else { - qWarning() << "Unknown candidate type" << typeStr; - if (ok) - *ok = false; - return HostType; - } - if (ok) - *ok = true; - return type; -} - -QString QXmppJingleCandidate::typeToString(QXmppJingleCandidate::Type type) -{ - QString typeStr; - switch (type) - { - case HostType: - typeStr = "host"; - break; - case PeerReflexiveType: - typeStr = "prflx"; - break; - case ServerReflexiveType: - typeStr = "srflx"; - break; - case RelayedType: - typeStr = "relay"; - break; - } - return typeStr; -} - -QXmppJinglePayloadType::QXmppJinglePayloadType() - : m_channels(1), - m_clockrate(0), - m_id(0), - m_maxptime(0), - m_ptime(0) -{ -} - -/// Returns the number of channels (e.g. 1 for mono, 2 for stereo). -/// - -unsigned char QXmppJinglePayloadType::channels() const -{ - return m_channels; -} - -/// Sets the number of channels (e.g. 1 for mono, 2 for stereo). -/// -/// \param channels - -void QXmppJinglePayloadType::setChannels(unsigned char channels) -{ - m_channels = channels; -} - -/// Returns the clockrate in Hz, i.e. the number of samples per second. -/// - -unsigned int QXmppJinglePayloadType::clockrate() const -{ - return m_clockrate; -} - -/// Sets the clockrate in Hz, i.e. the number of samples per second. -/// -/// \param clockrate - -void QXmppJinglePayloadType::setClockrate(unsigned int clockrate) -{ - m_clockrate = clockrate; -} - -/// Returns the payload type identifier. -/// - -unsigned char QXmppJinglePayloadType::id() const -{ - return m_id; -} - -/// Sets the payload type identifier. -/// - -void QXmppJinglePayloadType::setId(unsigned char id) -{ - Q_ASSERT(id <= 127); - m_id = id; -} - -/// Returns the maximum packet time in milliseconds. -/// - -unsigned int QXmppJinglePayloadType::maxptime() const -{ - return m_maxptime; -} - -/// Sets the maximum packet type in milliseconds. -/// -/// \param maxptime - -void QXmppJinglePayloadType::setMaxptime(unsigned int maxptime) -{ - m_maxptime = maxptime; -} - -/// Returns the payload type name. -/// - -QString QXmppJinglePayloadType::name() const -{ - return m_name; -} - -/// Sets the payload type name. -/// -/// \param name - -void QXmppJinglePayloadType::setName(const QString &name) -{ - m_name = name; -} - -/// Returns the payload parameters. - -QMap QXmppJinglePayloadType::parameters() const -{ - return m_parameters; -} - -/// Sets the payload parameters. - -void QXmppJinglePayloadType::setParameters(const QMap ¶meters) -{ - m_parameters = parameters; -} - -/// Returns the packet time in milliseconds (20 by default). -/// - -unsigned int QXmppJinglePayloadType::ptime() const -{ - return m_ptime ? m_ptime : 20; -} - -/// Sets the packet time in milliseconds (20 by default). -/// -/// \param ptime - -void QXmppJinglePayloadType::setPtime(unsigned int ptime) -{ - m_ptime = ptime; -} - -void QXmppJinglePayloadType::parse(const QDomElement &element) -{ - m_id = element.attribute("id").toInt(); - m_name = element.attribute("name"); - m_channels = element.attribute("channels").toInt(); - if (!m_channels) - m_channels = 1; - m_clockrate = element.attribute("clockrate").toInt(); - m_maxptime = element.attribute("maxptime").toInt(); - m_ptime = element.attribute("ptime").toInt(); - - QDomElement child = element.firstChildElement("parameter"); - while (!child.isNull()) { - m_parameters.insert(child.attribute("name"), child.attribute("value")); - child = child.nextSiblingElement("parameter"); - } -} - -void QXmppJinglePayloadType::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("payload-type"); - helperToXmlAddAttribute(writer, "id", QString::number(m_id)); - helperToXmlAddAttribute(writer, "name", m_name); - if (m_channels > 1) - helperToXmlAddAttribute(writer, "channels", QString::number(m_channels)); - if (m_clockrate > 0) - helperToXmlAddAttribute(writer, "clockrate", QString::number(m_clockrate)); - if (m_maxptime > 0) - helperToXmlAddAttribute(writer, "maxptime", QString::number(m_maxptime)); - if (m_ptime > 0) - helperToXmlAddAttribute(writer, "ptime", QString::number(m_ptime)); - - foreach (const QString &key, m_parameters.keys()) { - writer->writeStartElement("parameter"); - writer->writeAttribute("name", key); - writer->writeAttribute("value", m_parameters.value(key)); - writer->writeEndElement(); - } - writer->writeEndElement(); -} - -/// Returns true if this QXmppJinglePayloadType and \a other refer to the same payload type. -/// -/// \param other - -bool QXmppJinglePayloadType::operator==(const QXmppJinglePayloadType &other) const -{ - // FIXME : what to do with m_ptime and m_maxptime? - if (m_id <= 95) - return other.m_id == m_id && other.m_clockrate == m_clockrate; - else - return other.m_channels == m_channels && - other.m_clockrate == m_clockrate && - other.m_name.toLower() == m_name.toLower(); -} diff --git a/src/QXmppJingleIq.h b/src/QXmppJingleIq.h deleted file mode 100644 index ef5b66ec..00000000 --- a/src/QXmppJingleIq.h +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPJINGLEIQ_H -#define QXMPPJINGLEIQ_H - -#include - -#include "QXmppIq.h" - -/// \brief The QXmppJinglePayloadType class represents a payload type -/// as specified by XEP-0167: Jingle RTP Sessions and RFC 5245. -/// - -class QXmppJinglePayloadType -{ -public: - QXmppJinglePayloadType(); - - unsigned char channels() const; - void setChannels(unsigned char channels); - - unsigned int clockrate() const; - void setClockrate(unsigned int clockrate); - - unsigned char id() const; - void setId(unsigned char id); - - unsigned int maxptime() const; - void setMaxptime(unsigned int maxptime); - - QString name() const; - void setName(const QString &name); - - QMap parameters() const; - void setParameters(const QMap ¶meters); - - unsigned int ptime() const; - void setPtime(unsigned int ptime); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - - bool operator==(const QXmppJinglePayloadType &other) const; - -private: - unsigned char m_channels; - unsigned int m_clockrate; - unsigned char m_id; - unsigned int m_maxptime; - QString m_name; - QMap m_parameters; - unsigned int m_ptime; -}; - -/// \brief The QXmppJingleCandidate class represents a transport candidate -/// as specified by XEP-0176: Jingle ICE-UDP Transport Method. -/// - -class QXmppJingleCandidate -{ -public: - /// This enum is used to describe a candidate's type. - enum Type - { - HostType, ///< Host candidate, a local address/port. - PeerReflexiveType, ///< Peer-reflexive candidate, - ///< the address/port as seen from the peer. - ServerReflexiveType, ///< Server-reflexive candidate, - ///< the address/port as seen by the STUN server - RelayedType, ///< Relayed candidate, a candidate from - ///< a TURN relay. - }; - - QXmppJingleCandidate(); - - int component() const; - void setComponent(int component); - - int foundation() const; - void setFoundation(int foundation); - - QHostAddress host() const; - void setHost(const QHostAddress &host); - - QString id() const; - void setId(const QString &id); - - int network() const; - void setNetwork(int network); - - quint16 port() const; - void setPort(quint16 port); - - int priority() const; - void setPriority(int priority); - - QString protocol() const; - void setProtocol(const QString &protocol); - - QXmppJingleCandidate::Type type() const; - void setType(QXmppJingleCandidate::Type); - - bool isNull() const; - - static QXmppJingleCandidate::Type typeFromString(const QString &typeStr, bool *ok = 0); - static QString typeToString(QXmppJingleCandidate::Type type); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - -private: - int m_component; - int m_foundation; - int m_generation; - QHostAddress m_host; - QString m_id; - int m_network; - quint16 m_port; - QString m_protocol; - int m_priority; - QXmppJingleCandidate::Type m_type; -}; - -/// \brief The QXmppJingleIq class represents an IQ used for initiating media -/// sessions as specified by XEP-0166: Jingle. -/// -/// \ingroup Stanzas - -class QXmppJingleIq : public QXmppIq -{ -public: - /// This enum is used to describe a Jingle action. - enum Action { - ContentAccept, - ContentAdd, - ContentModify, - ContentReject, - ContentRemove, - DescriptionInfo, - SecurityInfo, - SessionAccept, - SessionInfo, - SessionInitiate, - SessionTerminate, - TransportAccept, - TransportInfo, - TransportReject, - TransportReplace, - }; - - /// \internal - /// - /// The QXmppJingleIq::Content class represents the "content" element of a - /// QXmppJingleIq. - - class Content - { - public: - Content(); - - QString creator() const; - void setCreator(const QString &creator); - - QString name() const; - void setName(const QString &name); - - QString senders() const; - void setSenders(const QString &senders); - - // XEP-0167: Jingle RTP Sessions - QString descriptionMedia() const; - void setDescriptionMedia(const QString &media); - - void addPayloadType(const QXmppJinglePayloadType &payload); - QList payloadTypes() const; - void setPayloadTypes(const QList &payloadTypes); - - void addTransportCandidate(const QXmppJingleCandidate &candidate); - QList transportCandidates() const; - - QString transportUser() const; - void setTransportUser(const QString &user); - - QString transportPassword() const; - void setTransportPassword(const QString &password); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - - private: - QString m_creator; - QString m_disposition; - QString m_name; - QString m_senders; - - QString m_descriptionMedia; - QString m_descriptionType; - QString m_transportType; - QString m_transportUser; - QString m_transportPassword; - QList m_payloadTypes; - QList m_transportCandidates; - }; - - /// \internal - /// - /// The QXmppJingleIq::Reason class represents the "reason" element of a - /// QXmppJingleIq. - - class Reason - { - public: - enum Type { - None, - AlternativeSession, - Busy, - Cancel, - ConnectivityError, - Decline, - Expired, - FailedApplication, - FailedTransport, - GeneralError, - Gone, - IncompatibleParameters, - MediaError, - SecurityError, - Success, - Timeout, - UnsupportedApplications, - UnsupportedTransports, - }; - - Reason(); - - QString text() const; - void setText(const QString &text); - - Type type() const; - void setType(Type type); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - - private: - QString m_text; - Type m_type; - }; - - QXmppJingleIq(); - - Action action() const; - void setAction(Action action); - - QString initiator() const; - void setInitiator(const QString &initiator); - - QString responder() const; - void setResponder(const QString &responder); - - QString sid() const; - void setSid(const QString &sid); - - /// Returns a reference to the IQ's content element. - Content& content() { return m_content; }; - - /// Returns a const reference to the IQ's content element. - const Content& content() const { return m_content; }; - - /// Returns a reference to the IQ's reason element. - Reason& reason() { return m_reason; }; - - /// Returns a const reference to the IQ's reason element. - const Reason& reason() const { return m_reason; }; - - // XEP-0167: Jingle RTP Sessions - bool ringing() const; - void setRinging(bool ringing); - - /// \cond - static bool isJingleIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - Action m_action; - QString m_initiator; - QString m_responder; - QString m_sid; - - Content m_content; - Reason m_reason; - bool m_ringing; -}; - -#endif diff --git a/src/QXmppLogger.cpp b/src/QXmppLogger.cpp deleted file mode 100644 index 107f72d9..00000000 --- a/src/QXmppLogger.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include -#include -#include -#include -#include - -#include "QXmppLogger.h" - -QXmppLogger* QXmppLogger::m_logger = 0; - -static const char *typeName(QXmppLogger::MessageType type) -{ - switch (type) - { - case QXmppLogger::DebugMessage: - return "DEBUG"; - case QXmppLogger::InformationMessage: - return "INFO"; - case QXmppLogger::WarningMessage: - return "WARNING"; - case QXmppLogger::ReceivedMessage: - return "RECEIVED"; - case QXmppLogger::SentMessage: - return "SENT"; - default: - return ""; - } -} - -static QString formatted(QXmppLogger::MessageType type, const QString& text) -{ - return QDateTime::currentDateTime().toString() + " " + - QString::fromLatin1(typeName(type)) + " " + - text; -} - -/// Constructs a new QXmppLoggable. -/// -/// \param parent - -QXmppLoggable::QXmppLoggable(QObject *parent) - : QObject(parent) -{ - QXmppLoggable *logParent = qobject_cast(parent); - if (logParent) { - connect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), - logParent, SIGNAL(logMessage(QXmppLogger::MessageType,QString))); - } -} - -void QXmppLoggable::childEvent(QChildEvent *event) -{ - QXmppLoggable *child = qobject_cast(event->child()); - if (!child) - return; - - if (event->added()) { - connect(child, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), - this, SIGNAL(logMessage(QXmppLogger::MessageType,QString))); - } else if (event->removed()) { - disconnect(child, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), - this, SIGNAL(logMessage(QXmppLogger::MessageType,QString))); - } -} - -class QXmppLoggerPrivate -{ -public: - QXmppLoggerPrivate(QXmppLogger *qq); - - QXmppLogger::LoggingType loggingType; - QFile *logFile; - QString logFilePath; - QXmppLogger::MessageTypes messageTypes; - -private: - QXmppLogger *q; -}; - -QXmppLoggerPrivate::QXmppLoggerPrivate(QXmppLogger *qq) - : loggingType(QXmppLogger::NoLogging), - logFile(0), - logFilePath("QXmppClientLog.log"), - messageTypes(QXmppLogger::AnyMessage), - q(qq) -{ -} - -/// Constructs a new QXmppLogger. -/// -/// \param parent - -QXmppLogger::QXmppLogger(QObject *parent) - : QObject(parent) -{ - d = new QXmppLoggerPrivate(this); - - // make it possible to pass QXmppLogger::MessageType between threads - qRegisterMetaType< QXmppLogger::MessageType >("QXmppLogger::MessageType"); -} - -QXmppLogger::~QXmppLogger() -{ - delete d; -} - -/// Returns the default logger. -/// - -QXmppLogger* QXmppLogger::getLogger() -{ - if(!m_logger) - m_logger = new QXmppLogger(); - - return m_logger; -} - -/// Returns the handler for logging messages. -/// - -QXmppLogger::LoggingType QXmppLogger::loggingType() -{ - return d->loggingType; -} - -/// Sets the handler for logging messages. -/// -/// \param type - -void QXmppLogger::setLoggingType(QXmppLogger::LoggingType type) -{ - if (d->loggingType != type) { - d->loggingType = type; - reopen(); - } -} - -/// Returns the types of messages to log. -/// - -QXmppLogger::MessageTypes QXmppLogger::messageTypes() -{ - return d->messageTypes; -} - -/// Sets the types of messages to log. -/// -/// \param types - -void QXmppLogger::setMessageTypes(QXmppLogger::MessageTypes types) -{ - d->messageTypes = types; -} - -/// Add a logging message. -/// -/// \param type -/// \param text - -void QXmppLogger::log(QXmppLogger::MessageType type, const QString& text) -{ - // filter messages - if (!d->messageTypes.testFlag(type)) - return; - - switch(d->loggingType) - { - case QXmppLogger::FileLogging: - if (!d->logFile) { - d->logFile = new QFile(d->logFilePath); - d->logFile->open(QIODevice::WriteOnly | QIODevice::Append); - } - QTextStream(d->logFile) << formatted(type, text) << "\n"; - break; - case QXmppLogger::StdoutLogging: - std::cout << qPrintable(formatted(type, text)) << std::endl; - break; - case QXmppLogger::SignalLogging: - emit message(type, text); - break; - default: - break; - } -} - -/// Returns the path to which logging messages should be written. -/// -/// \sa loggingType() - -QString QXmppLogger::logFilePath() -{ - return d->logFilePath; -} - -/// Sets the path to which logging messages should be written. -/// -/// \param path -/// -/// \sa setLoggingType() - -void QXmppLogger::setLogFilePath(const QString &path) -{ - if (d->logFilePath != path) { - d->logFilePath = path; - reopen(); - } -} - -/// If logging to a file, causes the file to be re-opened. -/// - -void QXmppLogger::reopen() -{ - if (d->logFile) { - delete d->logFile; - d->logFile = 0; - } -} - diff --git a/src/QXmppLogger.h b/src/QXmppLogger.h deleted file mode 100644 index 93de33f7..00000000 --- a/src/QXmppLogger.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPLOGGER_H -#define QXMPPLOGGER_H - -#include - -#ifdef QXMPP_LOGGABLE_TRACE -#define qxmpp_loggable_trace(x) QString("%1(0x%2) %3").arg(metaObject()->className(), QString::number(reinterpret_cast(this), 16), x) -#else -#define qxmpp_loggable_trace(x) (x) -#endif - -class QXmppLoggerPrivate; - -/// \brief The QXmppLogger class represents a sink for logging messages. -/// -/// \ingroup Core - -class QXmppLogger : public QObject -{ - Q_OBJECT - Q_ENUMS(LoggingType) - Q_FLAGS(MessageType MessageTypes) - Q_PROPERTY(QString logFilePath READ logFilePath WRITE setLogFilePath) - Q_PROPERTY(LoggingType loggingType READ loggingType WRITE setLoggingType) - Q_PROPERTY(MessageTypes messageTypes READ messageTypes WRITE setMessageTypes) - -public: - /// This enum describes how log message are handled. - enum LoggingType - { - NoLogging = 0, ///< Log messages are discarded - FileLogging = 1, ///< Log messages are written to a file - StdoutLogging = 2, ///< Log messages are written to the standard output - SignalLogging = 4, ///< Log messages are emitted as a signal - }; - - /// This enum describes a type of log message. - enum MessageType - { - NoMessage = 0, ///< No message type - DebugMessage = 1, ///< Debugging message - InformationMessage = 2, ///< Informational message - WarningMessage = 4, ///< Warning message - ReceivedMessage = 8, ///< Message received from server - SentMessage = 16, ///< Message sent to server - AnyMessage = 31, ///< Any message type - }; - Q_DECLARE_FLAGS(MessageTypes, MessageType) - - QXmppLogger(QObject *parent = 0); - ~QXmppLogger(); - - static QXmppLogger* getLogger(); - - QXmppLogger::LoggingType loggingType(); - void setLoggingType(QXmppLogger::LoggingType type); - - QString logFilePath(); - void setLogFilePath(const QString &path); - - QXmppLogger::MessageTypes messageTypes(); - void setMessageTypes(QXmppLogger::MessageTypes types); - -public slots: - void log(QXmppLogger::MessageType type, const QString& text); - void reopen(); - -signals: - /// This signal is emitted whenever a log message is received. - void message(QXmppLogger::MessageType type, const QString &text); - -private: - static QXmppLogger* m_logger; - QXmppLoggerPrivate *d; -}; - -/// \brief The QXmppLoggable class represents a source of logging messages. -/// -/// \ingroup Core - -class QXmppLoggable : public QObject -{ - Q_OBJECT - -public: - QXmppLoggable(QObject *parent = 0); - -protected: - /// \cond - virtual void childEvent(QChildEvent *event); - /// \endcond - - /// Logs a debugging message. - /// - /// \param message - - void debug(const QString &message) - { - emit logMessage(QXmppLogger::DebugMessage, qxmpp_loggable_trace(message)); - } - - /// Logs an informational message. - /// - /// \param message - - void info(const QString &message) - { - emit logMessage(QXmppLogger::InformationMessage, qxmpp_loggable_trace(message)); - } - - /// Logs a warning message. - /// - /// \param message - - void warning(const QString &message) - { - emit logMessage(QXmppLogger::WarningMessage, qxmpp_loggable_trace(message)); - } - - /// Logs a received packet. - /// - /// \param message - - void logReceived(const QString &message) - { - emit logMessage(QXmppLogger::ReceivedMessage, qxmpp_loggable_trace(message)); - } - - /// Logs a sent packet. - /// - /// \param message - - void logSent(const QString &message) - { - emit logMessage(QXmppLogger::SentMessage, qxmpp_loggable_trace(message)); - } - -signals: - /// This signal is emitted to send logging messages. - void logMessage(QXmppLogger::MessageType type, const QString &msg); -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QXmppLogger::MessageTypes) -#endif // QXMPPLOGGER_H diff --git a/src/QXmppMessage.cpp b/src/QXmppMessage.cpp deleted file mode 100644 index 109c0d84..00000000 --- a/src/QXmppMessage.cpp +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include -#include - -#include "QXmppConstants.h" -#include "QXmppMessage.h" -#include "QXmppUtils.h" - -static const char* chat_states[] = { - "", - "active", - "inactive", - "gone", - "composing", - "paused", -}; - -/// Constructs a QXmppMessage. -/// -/// \param from -/// \param to -/// \param body -/// \param thread - -QXmppMessage::QXmppMessage(const QString& from, const QString& to, const - QString& body, const QString& thread) - : QXmppStanza(from, to), - m_type(Chat), - m_stampType(QXmppMessage::DelayedDelivery), - m_state(None), - m_attentionRequested(false), - m_body(body), - m_thread(thread), - m_receiptRequested(false) -{ -} - -QXmppMessage::~QXmppMessage() -{ - -} - -/// Returns the message's body. -/// - -QString QXmppMessage::body() const -{ - return m_body; -} - -/// Sets the message's body. -/// -/// \param body - -void QXmppMessage::setBody(const QString& body) -{ - m_body = body; -} - -/// Returns true if the user's attention is requested, as defined -/// by XEP-0224: Attention. - -bool QXmppMessage::isAttentionRequested() const -{ - return m_attentionRequested; -} - -/// Sets whether the user's attention is requested, as defined -/// by XEP-0224: Attention. -/// -/// \a param requested - -void QXmppMessage::setAttentionRequested(bool requested) -{ - m_attentionRequested = requested; -} - -/// Returns true if a delivery receipt is requested, as defined -/// by XEP-0184: Message Delivery Receipts. - -bool QXmppMessage::isReceiptRequested() const -{ - return m_receiptRequested; -} - -/// Sets whether a delivery receipt is requested, as defined -/// by XEP-0184: Message Delivery Receipts. -/// -/// \a param requested - -void QXmppMessage::setReceiptRequested(bool requested) -{ - m_receiptRequested = requested; - if (requested && id().isEmpty()) - generateAndSetNextId(); -} - -/// If this message is a delivery receipt, returns the ID of the -/// original message. - -QString QXmppMessage::receiptId() const -{ - return m_receiptId; -} - -/// Make this message a delivery receipt for the message with -/// the given \a id. - -void QXmppMessage::setReceiptId(const QString &id) -{ - m_receiptId = id; -} - -/// Returns the message's type. -/// - -QXmppMessage::Type QXmppMessage::type() const -{ - return m_type; -} - -QString QXmppMessage::getTypeStr() const -{ - switch(m_type) - { - case QXmppMessage::Error: - return "error"; - case QXmppMessage::Normal: - return "normal"; - case QXmppMessage::Chat: - return "chat"; - case QXmppMessage::GroupChat: - return "groupchat"; - case QXmppMessage::Headline: - return "headline"; - default: - qWarning("QXmppMessage::getTypeStr() invalid type %d", (int)m_type); - return ""; - } -} - -/// Sets the message's type. -/// -/// \param type - -void QXmppMessage::setType(QXmppMessage::Type type) -{ - m_type = type; -} - -void QXmppMessage::setTypeFromStr(const QString& str) -{ - if(str == "error") - { - setType(QXmppMessage::Error); - return; - } - else if(str == "") // if no type is specified - { - setType(QXmppMessage::Normal); - return; - } - else if(str == "normal") - { - setType(QXmppMessage::Normal); - return; - } - else if(str == "chat") - { - setType(QXmppMessage::Chat); - return; - } - else if(str == "groupchat") - { - setType(QXmppMessage::GroupChat); - return; - } - else if(str == "headline") - { - setType(QXmppMessage::Headline); - return; - } - else - { - setType(static_cast(-1)); - qWarning("QXmppMessage::setTypeFromStr() invalid input string type: %s", - qPrintable(str)); - return; - } -} - -/// Returns the message's timestamp (if any). - -QDateTime QXmppMessage::stamp() const -{ - return m_stamp; -} - -/// Sets the message's timestamp. -/// -/// \param stamp - -void QXmppMessage::setStamp(const QDateTime &stamp) -{ - m_stamp = stamp; -} - -/// Returns the message's chat state. -/// - -QXmppMessage::State QXmppMessage::state() const -{ - return m_state; -} - -/// Sets the message's chat state. -/// -/// \param state - -void QXmppMessage::setState(QXmppMessage::State state) -{ - m_state = state; -} - -void QXmppMessage::parse(const QDomElement &element) -{ - QXmppStanza::parse(element); - - setTypeFromStr(element.attribute("type")); - m_body = element.firstChildElement("body").text(); - m_subject = element.firstChildElement("subject").text(); - m_thread = element.firstChildElement("thread").text(); - - // chat states - for (int i = Active; i <= Paused; i++) - { - QDomElement stateElement = element.firstChildElement(chat_states[i]); - if (!stateElement.isNull() && - stateElement.namespaceURI() == ns_chat_states) - { - m_state = static_cast(i); - break; - } - } - - // XEP-0184: Message Delivery Receipts - QDomElement receivedElement = element.firstChildElement("received"); - if (!receivedElement.isNull() && receivedElement.namespaceURI() == ns_message_receipts) { - m_receiptId = receivedElement.attribute("id"); - - // compatibility with old-style XEP - if (m_receiptId.isEmpty()) - m_receiptId = id(); - } else { - m_receiptId = QString(); - } - m_receiptRequested = element.firstChildElement("request").namespaceURI() == ns_message_receipts; - - // XEP-0203: Delayed Delivery - QDomElement delayElement = element.firstChildElement("delay"); - if (!delayElement.isNull() && delayElement.namespaceURI() == ns_delayed_delivery) - { - const QString str = delayElement.attribute("stamp"); - m_stamp = datetimeFromString(str); - m_stampType = QXmppMessage::DelayedDelivery; - } - - // XEP-0224: Attention - m_attentionRequested = element.firstChildElement("attention").namespaceURI() == ns_attention; - - QXmppElementList extensions; - QDomElement xElement = element.firstChildElement("x"); - while (!xElement.isNull()) - { - if (xElement.namespaceURI() == ns_legacy_delayed_delivery) - { - // XEP-0091: Legacy Delayed Delivery - const QString str = xElement.attribute("stamp"); - m_stamp = QDateTime::fromString(str, "yyyyMMddThh:mm:ss"); - m_stamp.setTimeSpec(Qt::UTC); - m_stampType = QXmppMessage::LegacyDelayedDelivery; - } else { - // other extensions - extensions << QXmppElement(xElement); - } - xElement = xElement.nextSiblingElement("x"); - } - setExtensions(extensions); -} - -void QXmppMessage::toXml(QXmlStreamWriter *xmlWriter) const -{ - - xmlWriter->writeStartElement("message"); - helperToXmlAddAttribute(xmlWriter, "xml:lang", lang()); - helperToXmlAddAttribute(xmlWriter, "id", id()); - helperToXmlAddAttribute(xmlWriter, "to", to()); - helperToXmlAddAttribute(xmlWriter, "from", from()); - helperToXmlAddAttribute(xmlWriter, "type", getTypeStr()); - if (!m_subject.isEmpty()) - helperToXmlAddTextElement(xmlWriter, "subject", m_subject); - if (!m_body.isEmpty()) - helperToXmlAddTextElement(xmlWriter, "body", m_body); - if (!m_thread.isEmpty()) - helperToXmlAddTextElement(xmlWriter, "thread", m_thread); - error().toXml(xmlWriter); - - // chat states - if (m_state > None && m_state <= Paused) - { - xmlWriter->writeStartElement(chat_states[m_state]); - xmlWriter->writeAttribute("xmlns", ns_chat_states); - xmlWriter->writeEndElement(); - } - - // time stamp - if (m_stamp.isValid()) - { - QDateTime utcStamp = m_stamp.toUTC(); - if (m_stampType == QXmppMessage::DelayedDelivery) - { - // XEP-0203: Delayed Delivery - xmlWriter->writeStartElement("delay"); - xmlWriter->writeAttribute("xmlns", ns_delayed_delivery); - helperToXmlAddAttribute(xmlWriter, "stamp", datetimeToString(utcStamp)); - xmlWriter->writeEndElement(); - } else { - // XEP-0091: Legacy Delayed Delivery - xmlWriter->writeStartElement("x"); - xmlWriter->writeAttribute("xmlns", ns_legacy_delayed_delivery); - helperToXmlAddAttribute(xmlWriter, "stamp", utcStamp.toString("yyyyMMddThh:mm:ss")); - xmlWriter->writeEndElement(); - } - } - - // XEP-0184: Message Delivery Receipts - if (!m_receiptId.isEmpty()) { - xmlWriter->writeStartElement("received"); - xmlWriter->writeAttribute("xmlns", ns_message_receipts); - xmlWriter->writeAttribute("id", m_receiptId); - xmlWriter->writeEndElement(); - } - if (m_receiptRequested) { - xmlWriter->writeStartElement("request"); - xmlWriter->writeAttribute("xmlns", ns_message_receipts); - xmlWriter->writeEndElement(); - } - - // XEP-0224: Attention - if (m_attentionRequested) { - xmlWriter->writeStartElement("attention"); - xmlWriter->writeAttribute("xmlns", ns_attention); - xmlWriter->writeEndElement(); - } - - // other extensions - foreach (const QXmppElement &extension, extensions()) - extension.toXml(xmlWriter); - xmlWriter->writeEndElement(); -} - -/// Returns the message's subject. -/// - -QString QXmppMessage::subject() const -{ - return m_subject; -} - -/// Sets the message's subject. -/// -/// \param subject - -void QXmppMessage::setSubject(const QString& subject) -{ - m_subject = subject; -} - -/// Returns the message's thread. - -QString QXmppMessage::thread() const -{ - return m_thread; -} - -/// Sets the message's thread. -/// -/// \param thread - -void QXmppMessage::setThread(const QString& thread) -{ - m_thread = thread; -} - diff --git a/src/QXmppMessage.h b/src/QXmppMessage.h deleted file mode 100644 index a981f1db..00000000 --- a/src/QXmppMessage.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPMESSAGE_H -#define QXMPPMESSAGE_H - -#include -#include "QXmppStanza.h" - -/// \brief The QXmppMessage class represents an XMPP message. -/// -/// \ingroup Stanzas -/// - -class QXmppMessage : public QXmppStanza -{ -public: - /// This enum described a message type. - enum Type - { - Error = 0, - Normal, - Chat, - GroupChat, - Headline - }; - - /// This enum describes a chat state as defined by - /// XEP-0085 : Chat State Notifications. - enum State - { - None = 0, ///< The message does not contain any chat state information. - Active, ///< User is actively participating in the chat session. - Inactive, ///< User has not been actively participating in the chat session. - Gone, ///< User has effectively ended their participation in the chat session. - Composing, ///< User is composing a message. - Paused, ///< User had been composing but now has stopped. - }; - - QXmppMessage(const QString& from = "", const QString& to = "", - const QString& body = "", const QString& thread = ""); - ~QXmppMessage(); - - QString body() const; - void setBody(const QString&); - - bool isAttentionRequested() const; - void setAttentionRequested(bool requested); - - bool isReceiptRequested() const; - void setReceiptRequested(bool requested); - - QString receiptId() const; - void setReceiptId(const QString &id); - - QDateTime stamp() const; - void setStamp(const QDateTime &stamp); - - QXmppMessage::State state() const; - void setState(QXmppMessage::State); - - QString subject() const; - void setSubject(const QString&); - - QString thread() const; - void setThread(const QString&); - - QXmppMessage::Type type() const; - void setType(QXmppMessage::Type); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - -private: - /// This enum describe a type of message timestamp. - enum StampType - { - LegacyDelayedDelivery, ///< XEP-0091: Legacy Delayed Delivery - DelayedDelivery, ///< XEP-0203: Delayed Delivery - }; - - QString getTypeStr() const; - void setTypeFromStr(const QString&); - - Type m_type; - QDateTime m_stamp; - StampType m_stampType; - State m_state; - - bool m_attentionRequested; - QString m_body; - QString m_subject; - QString m_thread; - - // Request message receipt as per XEP-0184. - QString m_receiptId; - bool m_receiptRequested; -}; - -#endif // QXMPPMESSAGE_H diff --git a/src/QXmppMucIq.cpp b/src/QXmppMucIq.cpp deleted file mode 100644 index 97328a2f..00000000 --- a/src/QXmppMucIq.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include "QXmppConstants.h" -#include "QXmppMucIq.h" -#include "QXmppUtils.h" - -QXmppMucItem::QXmppMucItem() - : m_affiliation(QXmppMucItem::UnspecifiedAffiliation), - m_role(QXmppMucItem::UnspecifiedRole) -{ -} - -bool QXmppMucItem::isNull() const -{ - return m_actor.isEmpty() && - m_affiliation == UnspecifiedAffiliation && - m_jid.isEmpty() && - m_nick.isEmpty() && - m_reason.isEmpty() && - m_role == UnspecifiedRole; -} - -QString QXmppMucItem::actor() const -{ - return m_actor; -} - -void QXmppMucItem::setActor(const QString &actor) -{ - m_actor = actor; -} - -/// Returns the user's affiliation, i.e. long-lived permissions. - -QXmppMucItem::Affiliation QXmppMucItem::affiliation() const -{ - return m_affiliation; -} - -QXmppMucItem::Affiliation QXmppMucItem::affiliationFromString(const QString &affiliationStr) -{ - if (affiliationStr == "owner") - return QXmppMucItem::OwnerAffiliation; - else if (affiliationStr == "admin") - return QXmppMucItem::AdminAffiliation; - else if (affiliationStr == "member") - return QXmppMucItem::MemberAffiliation; - else if (affiliationStr == "outcast") - return QXmppMucItem::OutcastAffiliation; - else if (affiliationStr == "none") - return QXmppMucItem::NoAffiliation; - else - return QXmppMucItem::UnspecifiedAffiliation; -} - -QString QXmppMucItem::affiliationToString(Affiliation affiliation) -{ - switch (affiliation) { - case QXmppMucItem::OwnerAffiliation: - return "owner"; - case QXmppMucItem::AdminAffiliation: - return "admin"; - case QXmppMucItem::MemberAffiliation: - return "member"; - case QXmppMucItem::OutcastAffiliation: - return "outcast"; - case QXmppMucItem::NoAffiliation: - return "none"; - default: - return QString(); - } -} - -/// Sets the user's affiliation, i.e. long-lived permissions. -/// -/// \param affiliation - -void QXmppMucItem::setAffiliation(Affiliation affiliation) -{ - m_affiliation = affiliation; -} - -/// Returns the user's real JID. - -QString QXmppMucItem::jid() const -{ - return m_jid; -} - -/// Sets the user's real JID. -/// -/// \param jid - -void QXmppMucItem::setJid(const QString &jid) -{ - m_jid = jid; -} - -/// Returns the user's nickname. - -QString QXmppMucItem::nick() const -{ - return m_nick; -} - -/// Sets the user's nickname. -/// -/// \param nick - -void QXmppMucItem::setNick(const QString &nick) -{ - m_nick = nick; -} - -QString QXmppMucItem::reason() const -{ - return m_reason; -} - -void QXmppMucItem::setReason(const QString &reason) -{ - m_reason = reason; -} - -/// Returns the user's role, i.e. short-lived permissions. - -QXmppMucItem::Role QXmppMucItem::role() const -{ - return m_role; -} - -QXmppMucItem::Role QXmppMucItem::roleFromString(const QString &roleStr) -{ - if (roleStr == "moderator") - return QXmppMucItem::ModeratorRole; - else if (roleStr == "participant") - return QXmppMucItem::ParticipantRole; - else if (roleStr == "visitor") - return QXmppMucItem::VisitorRole; - else if (roleStr == "none") - return QXmppMucItem::NoRole; - else - return QXmppMucItem::UnspecifiedRole; -} - -QString QXmppMucItem::roleToString(Role role) -{ - switch (role) { - case QXmppMucItem::ModeratorRole: - return "moderator"; - case QXmppMucItem::ParticipantRole: - return "participant"; - case QXmppMucItem::VisitorRole: - return "visitor"; - case QXmppMucItem::NoRole: - return "none"; - default: - return QString(); - } -} - -/// Sets the user's role, i.e. short-lived permissions. -/// -/// \param role - -void QXmppMucItem::setRole(Role role) -{ - m_role = role; -} - -void QXmppMucItem::parse(const QDomElement &element) -{ - m_affiliation = QXmppMucItem::affiliationFromString(element.attribute("affiliation").toLower()); - m_jid = element.attribute("jid"); - m_nick = element.attribute("nick"); - m_role = QXmppMucItem::roleFromString(element.attribute("role").toLower()); - m_actor = element.firstChildElement("actor").attribute("jid"); - m_reason = element.firstChildElement("reason").text(); -} - -void QXmppMucItem::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("item"); - helperToXmlAddAttribute(writer, "affiliation", affiliationToString(m_affiliation)); - helperToXmlAddAttribute(writer, "jid", m_jid); - helperToXmlAddAttribute(writer, "nick", m_nick); - helperToXmlAddAttribute(writer, "role", roleToString(m_role)); - if (!m_actor.isEmpty()) { - writer->writeStartElement("actor"); - helperToXmlAddAttribute(writer, "jid", m_actor); - writer->writeEndElement(); - } - if (!m_reason.isEmpty()) - helperToXmlAddTextElement(writer, "reason", m_reason); - writer->writeEndElement(); -} - -/// Returns the IQ's items. - -QList QXmppMucAdminIq::items() const -{ - return m_items; -} - -/// Sets the IQ's items. -/// -/// \param items - -void QXmppMucAdminIq::setItems(const QList &items) -{ - m_items = items; -} - -bool QXmppMucAdminIq::isMucAdminIq(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - return (queryElement.namespaceURI() == ns_muc_admin); -} - -void QXmppMucAdminIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - QDomElement child = queryElement.firstChildElement("item"); - while (!child.isNull()) - { - QXmppMucItem item; - item.parse(child); - m_items << item; - child = child.nextSiblingElement("item"); - } -} - -void QXmppMucAdminIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("query"); - writer->writeAttribute("xmlns", ns_muc_admin); - foreach (const QXmppMucItem &item, m_items) - item.toXml(writer); - writer->writeEndElement(); -} - -/// Returns the IQ's data form. - -QXmppDataForm QXmppMucOwnerIq::form() const -{ - return m_form; -} - -/// Sets the IQ's data form. -/// -/// \param form - -void QXmppMucOwnerIq::setForm(const QXmppDataForm &form) -{ - m_form = form; -} - -bool QXmppMucOwnerIq::isMucOwnerIq(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - return (queryElement.namespaceURI() == ns_muc_owner); -} - -void QXmppMucOwnerIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - m_form.parse(queryElement.firstChildElement("x")); -} - -void QXmppMucOwnerIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("query"); - writer->writeAttribute("xmlns", ns_muc_owner); - m_form.toXml(writer); - writer->writeEndElement(); -} - diff --git a/src/QXmppMucIq.h b/src/QXmppMucIq.h deleted file mode 100644 index 5e73fc9b..00000000 --- a/src/QXmppMucIq.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPMUCIQ_H -#define QXMPPMUCIQ_H - -#include "QXmppDataForm.h" -#include "QXmppIq.h" - -/// \brief The QXmppMucItem class represents a chat room "item". -/// -/// It is used to convey information such as permissions. -/// -/// \ingroup Stanzas - -class QXmppMucItem -{ -public: - /// This enum is used to represent long-lived permissions in a room (affiliations). - enum Affiliation { - UnspecifiedAffiliation, - OutcastAffiliation, - NoAffiliation, - MemberAffiliation, - AdminAffiliation, - OwnerAffiliation, - }; - - /// This enum is used to represent short-lived permissions in a room (roles). - enum Role { - UnspecifiedRole, - NoRole, - VisitorRole, - ParticipantRole, - ModeratorRole, - }; - - QXmppMucItem(); - bool isNull() const; - - QString actor() const; - void setActor(const QString &actor); - - Affiliation affiliation() const; - void setAffiliation(Affiliation affiliation); - - QString jid() const; - void setJid(const QString &jid); - - QString nick() const; - void setNick(const QString &nick); - - QString reason() const; - void setReason(const QString &reason); - - Role role() const; - void setRole(Role role); - - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - - /// \cond - static Affiliation affiliationFromString(const QString &affiliationStr); - static QString affiliationToString(Affiliation affiliation); - static Role roleFromString(const QString &roleStr); - static QString roleToString(Role role); - /// \endcond -private: - QString m_actor; - Affiliation m_affiliation; - QString m_jid; - QString m_nick; - QString m_reason; - Role m_role; -}; - -/// \brief The QXmppMucAdminIq class represents a chat room administration IQ -/// as defined by XEP-0045: Multi-User Chat. -/// -/// It is used to get or modify room memberships. -/// -/// \ingroup Stanzas - -class QXmppMucAdminIq : public QXmppIq -{ -public: - QList items() const; - void setItems(const QList &items); - - /// \cond - static bool isMucAdminIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QList m_items; -}; - -/// \brief The QXmppMucOwnerIq class represents a chat room configuration IQ as -/// defined by XEP-0045: Multi-User Chat. -/// -/// It is used to get or modify room configuration options. -/// -/// \sa QXmppDataForm -/// - -class QXmppMucOwnerIq : public QXmppIq -{ -public: - QXmppDataForm form() const; - void setForm(const QXmppDataForm &form); - - /// \cond - static bool isMucOwnerIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QXmppDataForm m_form; -}; - -#endif diff --git a/src/QXmppNonSASLAuth.cpp b/src/QXmppNonSASLAuth.cpp deleted file mode 100644 index 0dea6184..00000000 --- a/src/QXmppNonSASLAuth.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include -#include -#include - -#include "QXmppConstants.h" -#include "QXmppNonSASLAuth.h" -#include "QXmppUtils.h" - -QXmppNonSASLAuthIq::QXmppNonSASLAuthIq() - : QXmppIq(QXmppIq::Set) -{ -} - -bool QXmppNonSASLAuthIq::isNonSASLAuthIq(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - return queryElement.namespaceURI() == ns_auth; -} - -void QXmppNonSASLAuthIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - m_username = queryElement.firstChildElement("username").text(); - m_password = queryElement.firstChildElement("password").text(); - m_digest = QByteArray::fromHex(queryElement.firstChildElement("digest").text().toAscii()); - m_resource = queryElement.firstChildElement("resource").text(); -} - -void QXmppNonSASLAuthIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("query"); - writer->writeAttribute("xmlns", ns_auth); - if (!m_username.isEmpty()) - writer->writeTextElement("username", m_username); - if (!m_digest.isEmpty()) - writer->writeTextElement("digest", m_digest.toHex()); - if (!m_password.isEmpty()) - writer->writeTextElement("password", m_password); - if (!m_resource.isEmpty()) - writer->writeTextElement("resource", m_resource); - writer->writeEndElement(); -} - -QString QXmppNonSASLAuthIq::username() const -{ - return m_username; -} - -void QXmppNonSASLAuthIq::setUsername( const QString &username ) -{ - m_username = username; -} - -QByteArray QXmppNonSASLAuthIq::digest() const -{ - return m_digest; -} - -void QXmppNonSASLAuthIq::setDigest(const QString &streamId, const QString &password) -{ - m_digest = QCryptographicHash::hash(streamId.toUtf8() + password.toUtf8(), QCryptographicHash::Sha1); -} - -QString QXmppNonSASLAuthIq::password() const -{ - return m_password; -} - -void QXmppNonSASLAuthIq::setPassword( const QString &password ) -{ - m_password = password; -} - -QString QXmppNonSASLAuthIq::resource() const -{ - return m_resource; -} - -void QXmppNonSASLAuthIq::setResource(const QString &resource) -{ - m_resource = resource; -} - diff --git a/src/QXmppNonSASLAuth.h b/src/QXmppNonSASLAuth.h deleted file mode 100644 index a17436e7..00000000 --- a/src/QXmppNonSASLAuth.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXmppNonSASLAuth_H -#define QXmppNonSASLAuth_H - -#include "QXmppIq.h" - -class QXmppNonSASLAuthIq : public QXmppIq -{ -public: - QXmppNonSASLAuthIq(); - - QString username() const; - void setUsername(const QString &username); - - QByteArray digest() const; - void setDigest(const QString &streamId, const QString &password); - - QString password() const; - void setPassword(const QString &password); - - QString resource() const; - void setResource(const QString &resource); - - static bool isNonSASLAuthIq(const QDomElement &element); - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString m_username; - QByteArray m_digest; - QString m_password; - QString m_resource; -}; - -#endif // QXmppNonSASLAuth_H diff --git a/src/QXmppPacket.cpp b/src/QXmppPacket.cpp deleted file mode 100644 index 1d284325..00000000 --- a/src/QXmppPacket.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#include "QXmppPacket.h" - -QXmppPacket::QXmppPacket() -{ -} - -QXmppPacket::~QXmppPacket() -{ -} - diff --git a/src/QXmppPacket.h b/src/QXmppPacket.h deleted file mode 100644 index 427217c7..00000000 --- a/src/QXmppPacket.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPPACKET_H -#define QXMPPPACKET_H - -#include - -// forward declarations of QXmlStream* classes will not work on Mac, we need to -// include the whole header. -// See http://lists.trolltech.com/qt-interest/2008-07/thread00798-0.html -// for an explanation. -#include - -class QDomElement; - -class QXmppPacket -{ -public: - QXmppPacket(); - virtual ~QXmppPacket(); - - virtual void parse(const QDomElement &element) = 0; - virtual void toXml( QXmlStreamWriter *writer ) const = 0; -}; - -#endif // QXMPPPACKET_H diff --git a/src/QXmppPingIq.cpp b/src/QXmppPingIq.cpp deleted file mode 100644 index 7058c6d0..00000000 --- a/src/QXmppPingIq.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include "QXmppConstants.h" -#include "QXmppPingIq.h" -#include "QXmppUtils.h" - -#include - -QXmppPingIq::QXmppPingIq() : QXmppIq(QXmppIq::Get) -{ -} - -bool QXmppPingIq::isPingIq(const QDomElement &element) -{ - QDomElement pingElement = element.firstChildElement("ping"); - return (element.attribute("type") == "get" && - pingElement.namespaceURI() == ns_ping); -} - -void QXmppPingIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("ping"); - writer->writeAttribute("xmlns", ns_ping); - writer->writeEndElement(); -} - diff --git a/src/QXmppPingIq.h b/src/QXmppPingIq.h deleted file mode 100644 index 527eeb68..00000000 --- a/src/QXmppPingIq.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPPINGIQ_H -#define QXMPPPINGIQ_H - -#include "QXmppIq.h" - -class QXmlStreamWriter; -class QDomElement; - -class QXmppPingIq : public QXmppIq -{ -public: - QXmppPingIq(); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - static bool isPingIq(const QDomElement &element); -}; - -#endif diff --git a/src/QXmppPresence.cpp b/src/QXmppPresence.cpp deleted file mode 100644 index b967c8e5..00000000 --- a/src/QXmppPresence.cpp +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#include "QXmppPresence.h" -#include "QXmppUtils.h" -#include -#include -#include -#include "QXmppConstants.h" - -/// Constructs a QXmppPresence. -/// -/// \param type -/// \param status - -QXmppPresence::QXmppPresence(QXmppPresence::Type type, - const QXmppPresence::Status& status) - : QXmppStanza(), - m_type(type), - m_status(status), - m_vCardUpdateType(VCardUpdateNone) -{ - -} - -/// Destroys a QXmppPresence. - -QXmppPresence::~QXmppPresence() -{ - -} - -/// Returns the presence type. -/// -/// You can use this method to determine the action which needs to be -/// taken in response to receiving the presence. For instance, if the type is -/// QXmppPresence::Available or QXmppPresence::Unavailable, you could update -/// the icon representing a contact's availability. - -QXmppPresence::Type QXmppPresence::type() const -{ - return m_type; -} - -/// Sets the presence type. -/// -/// \param type - -void QXmppPresence::setType(QXmppPresence::Type type) -{ - m_type = type; -} - -/// Returns the presence status. - -const QXmppPresence::Status& QXmppPresence::status() const -{ - return m_status; -} - -/// Returns a reference to the presence status, allowing you to change it. - -QXmppPresence::Status& QXmppPresence::status() -{ - return m_status; -} - -/// Sets the presence status. -/// -/// \param status - -void QXmppPresence::setStatus(const QXmppPresence::Status& status) -{ - m_status = status; -} - -void QXmppPresence::parse(const QDomElement &element) -{ - QXmppStanza::parse(element); - - setTypeFromStr(element.attribute("type")); - m_status.parse(element); - - QXmppElementList extensions; - QDomElement xElement = element.firstChildElement(); - m_vCardUpdateType = VCardUpdateNone; - while(!xElement.isNull()) - { - // XEP-0045: Multi-User Chat - if(xElement.namespaceURI() == ns_muc_user) - { - QDomElement itemElement = xElement.firstChildElement("item"); - m_mucItem.parse(itemElement); - QDomElement statusElement = xElement.firstChildElement("status"); - m_mucStatusCodes.clear(); - while (!statusElement.isNull()) { - m_mucStatusCodes << statusElement.attribute("code").toInt(); - statusElement = statusElement.nextSiblingElement("status"); - } - } - // XEP-0153: vCard-Based Avatars - else if(xElement.namespaceURI() == ns_vcard_update) - { - QDomElement photoElement = xElement.firstChildElement("photo"); - if(!photoElement.isNull()) - { - m_photoHash = QByteArray::fromHex(photoElement.text().toAscii()); - if(m_photoHash.isEmpty()) - m_vCardUpdateType = VCardUpdateNoPhoto; - else - m_vCardUpdateType = VCardUpdateValidPhoto; - } - else - { - m_photoHash = QByteArray(); - m_vCardUpdateType = VCardUpdateNotReady; - } - } - // XEP-0115: Entity Capabilities - else if(xElement.tagName() == "c" && xElement.namespaceURI() == ns_capabilities) - { - m_capabilityNode = xElement.attribute("node"); - m_capabilityVer = QByteArray::fromBase64(xElement.attribute("ver").toAscii()); - m_capabilityHash = xElement.attribute("hash"); - m_capabilityExt = xElement.attribute("ext").split(" ", QString::SkipEmptyParts); - } - else if (xElement.tagName() == "error") - { - } - else if (xElement.tagName() == "show") - { - } - else if (xElement.tagName() == "status") - { - } - else if (xElement.tagName() == "priority") - { - } - else - { - // other extensions - extensions << QXmppElement(xElement); - } - xElement = xElement.nextSiblingElement(); - } - setExtensions(extensions); -} - -void QXmppPresence::toXml(QXmlStreamWriter *xmlWriter) const -{ - xmlWriter->writeStartElement("presence"); - helperToXmlAddAttribute(xmlWriter,"xml:lang", lang()); - helperToXmlAddAttribute(xmlWriter,"id", id()); - helperToXmlAddAttribute(xmlWriter,"to", to()); - helperToXmlAddAttribute(xmlWriter,"from", from()); - helperToXmlAddAttribute(xmlWriter,"type", getTypeStr()); - m_status.toXml(xmlWriter); - - error().toXml(xmlWriter); - - // XEP-0045: Multi-User Chat - if(!m_mucItem.isNull() || !m_mucStatusCodes.isEmpty()) - { - xmlWriter->writeStartElement("x"); - xmlWriter->writeAttribute("xmlns", ns_muc_user); - if (!m_mucItem.isNull()) - m_mucItem.toXml(xmlWriter); - foreach (int code, m_mucStatusCodes) { - xmlWriter->writeStartElement("status"); - xmlWriter->writeAttribute("code", QString::number(code)); - xmlWriter->writeEndElement(); - } - xmlWriter->writeEndElement(); - } - - // XEP-0153: vCard-Based Avatars - if(m_vCardUpdateType != VCardUpdateNone) - { - xmlWriter->writeStartElement("x"); - xmlWriter->writeAttribute("xmlns", ns_vcard_update); - switch(m_vCardUpdateType) - { - case VCardUpdateNoPhoto: - helperToXmlAddTextElement(xmlWriter, "photo", ""); - break; - case VCardUpdateValidPhoto: - helperToXmlAddTextElement(xmlWriter, "photo", m_photoHash.toHex()); - break; - case VCardUpdateNotReady: - break; - default: - break; - } - xmlWriter->writeEndElement(); - } - - if(!m_capabilityNode.isEmpty() && !m_capabilityVer.isEmpty() - && !m_capabilityHash.isEmpty()) - { - xmlWriter->writeStartElement("c"); - xmlWriter->writeAttribute("xmlns", ns_capabilities); - helperToXmlAddAttribute(xmlWriter, "hash", m_capabilityHash); - helperToXmlAddAttribute(xmlWriter, "node", m_capabilityNode); - helperToXmlAddAttribute(xmlWriter, "ver", m_capabilityVer.toBase64()); - xmlWriter->writeEndElement(); - } - - foreach (const QXmppElement &extension, extensions()) - extension.toXml(xmlWriter); - - xmlWriter->writeEndElement(); -} - -QString QXmppPresence::getTypeStr() const -{ - switch(m_type) { - case QXmppPresence::Error: - return "error"; - case QXmppPresence::Available: - return ""; - case QXmppPresence::Unavailable: - return "unavailable"; - case QXmppPresence::Subscribe: - return "subscribe"; - case QXmppPresence::Subscribed: - return "subscribed"; - case QXmppPresence::Unsubscribe: - return "unsubscribe"; - case QXmppPresence::Unsubscribed: - return "unsubscribed"; - case QXmppPresence::Probe: - return "probe"; - default: - qWarning("QXmppPresence::getTypeStr() invalid type %d", (int)m_type); - return ""; - } -} - -void QXmppPresence::setTypeFromStr(const QString& str) -{ - if(str == "error") - m_type = QXmppPresence::Error; - else if(str == "") - m_type = QXmppPresence::Available; - else if(str == "unavailable") - m_type = QXmppPresence::Unavailable; - else if(str == "subscribe") - m_type = QXmppPresence::Subscribe; - else if(str == "subscribed") - m_type = QXmppPresence::Subscribed; - else if(str == "unsubscribe") - m_type = QXmppPresence::Unsubscribe; - else if(str == "unsubscribed") - m_type = QXmppPresence::Unsubscribed; - else if(str == "probe") - m_type = QXmppPresence::Probe; - else { - qWarning("QXmppPresence::setTypeFromStr() invalid input string type: %s", - qPrintable(str)); - m_type = QXmppPresence::Error; - } -} - -/// Constructs a presence status. - -QXmppPresence::Status::Status(QXmppPresence::Status::Type type, - const QString statusText, int priority) : - m_type(type), - m_statusText(statusText), m_priority(priority) -{ -} - -/// Returns the status type, for instance busy or away. - -QXmppPresence::Status::Type QXmppPresence::Status::type() const -{ - return m_type; -} - -/// Sets the status type. - -void QXmppPresence::Status::setType(QXmppPresence::Status::Type type) -{ - m_type = type; -} - -void QXmppPresence::Status::setTypeFromStr(const QString& str) -{ - // FIXME: there is no keyword for Offline - if(str == "") - m_type = QXmppPresence::Status::Online; - else if(str == "away") - m_type = QXmppPresence::Status::Away; - else if(str == "chat") - m_type = QXmppPresence::Status::Chat; - else if(str == "dnd") - m_type = QXmppPresence::Status::DND; - else if(str == "xa") - m_type = QXmppPresence::Status::XA; - else { - qWarning("QXmppPresence::Status::setTypeFromStr() invalid input string type %s", - qPrintable(str)); - m_type = QXmppPresence::Status::Online; - } -} - -QString QXmppPresence::Status::getTypeStr() const -{ - switch(m_type) { - case QXmppPresence::Status::Online: - return ""; - case QXmppPresence::Status::Offline: - // FIXME: there is no keyword for Offline - return ""; - case QXmppPresence::Status::Away: - return "away"; - case QXmppPresence::Status::XA: - return "xa"; - case QXmppPresence::Status::DND: - return "dnd"; - case QXmppPresence::Status::Chat: - return "chat"; - default: - qWarning("QXmppPresence::Status::getTypeStr() invalid type %d", - (int)m_type); - return ""; - } -} - -/// Returns the status text, a textual description of the user's status. - -QString QXmppPresence::Status::statusText() const -{ - return m_statusText; -} - -/// Sets the status text, a textual description of the user's status. -/// -/// \param str The status text, for example "Gone fishing". - -void QXmppPresence::Status::setStatusText(const QString& str) -{ - m_statusText = str; -} - -/// Returns the priority level of the resource. - -int QXmppPresence::Status::priority() const -{ - return m_priority; -} - -/// Sets the priority level of the resource. -/// -/// \param priority - -void QXmppPresence::Status::setPriority(int priority) -{ - m_priority = priority; -} - -void QXmppPresence::Status::parse(const QDomElement &element) -{ - setTypeFromStr(element.firstChildElement("show").text()); - m_statusText = element.firstChildElement("status").text(); - m_priority = element.firstChildElement("priority").text().toInt(); -} - -void QXmppPresence::Status::toXml(QXmlStreamWriter *xmlWriter) const -{ - const QString show = getTypeStr(); - if (!show.isEmpty()) - helperToXmlAddTextElement(xmlWriter, "show", getTypeStr()); - if (!m_statusText.isEmpty()) - helperToXmlAddTextElement(xmlWriter, "status", m_statusText); - if (m_priority != 0) - helperToXmlAddTextElement(xmlWriter, "priority", QString::number(m_priority)); -} - -/// Returns the photo-hash of the VCardUpdate. -/// -/// \return QByteArray - -QByteArray QXmppPresence::photoHash() const -{ - return m_photoHash; -} - -/// Sets the photo-hash of the VCardUpdate. -/// -/// \param photoHash as QByteArray - -void QXmppPresence::setPhotoHash(const QByteArray& photoHash) -{ - m_photoHash = photoHash; -} - -/// Returns the type of VCardUpdate -/// -/// \return VCardUpdateType - -QXmppPresence::VCardUpdateType QXmppPresence::vCardUpdateType() const -{ - return m_vCardUpdateType; -} - -/// Sets the type of VCardUpdate -/// -/// \param type VCardUpdateType - -void QXmppPresence::setVCardUpdateType(VCardUpdateType type) -{ - m_vCardUpdateType = type; -} - -/// XEP-0115: Entity Capabilities -QString QXmppPresence::capabilityHash() const -{ - return m_capabilityHash; -} - -/// XEP-0115: Entity Capabilities -void QXmppPresence::setCapabilityHash(const QString& hash) -{ - m_capabilityHash = hash; -} - -/// XEP-0115: Entity Capabilities -QString QXmppPresence::capabilityNode() const -{ - return m_capabilityNode; -} - -/// XEP-0115: Entity Capabilities -void QXmppPresence::setCapabilityNode(const QString& node) -{ - m_capabilityNode = node; -} - -/// XEP-0115: Entity Capabilities -QByteArray QXmppPresence::capabilityVer() const -{ - return m_capabilityVer; -} - -/// XEP-0115: Entity Capabilities -void QXmppPresence::setCapabilityVer(const QByteArray& ver) -{ - m_capabilityVer = ver; -} - -/// Legacy XEP-0115: Entity Capabilities -QStringList QXmppPresence::capabilityExt() const -{ - return m_capabilityExt; -} - -/// Returns the MUC item. - -QXmppMucItem QXmppPresence::mucItem() const -{ - return m_mucItem; -} - -/// Sets the MUC item. -/// -/// \param item - -void QXmppPresence::setMucItem(const QXmppMucItem &item) -{ - m_mucItem = item; -} - -/// Returns the MUC status codes. - -QList QXmppPresence::mucStatusCodes() const -{ - return m_mucStatusCodes; -} - -/// Sets the MUC status codes. -/// -/// \param codes - -void QXmppPresence::setMucStatusCodes(const QList &codes) -{ - m_mucStatusCodes = codes; -} - diff --git a/src/QXmppPresence.h b/src/QXmppPresence.h deleted file mode 100644 index 8b85e01b..00000000 --- a/src/QXmppPresence.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPPRESENCE_H -#define QXMPPPRESENCE_H - -#include "QXmppStanza.h" -#include "QXmppMucIq.h" - -/// \brief The QXmppPresence class represents an XMPP presence stanza. -/// -/// \ingroup Stanzas -class QXmppPresence : public QXmppStanza -{ -public: - /// This enum is used to describe a presence type. - enum Type - { - Error = 0, ///< An error has occurred regarding processing or delivery of a previously-sent presence stanza. - Available, ///< Signals that the sender is online and available for communication. - Unavailable, ///< Signals that the sender is no longer available for communication. - Subscribe, ///< The sender wishes to subscribe to the recipient's presence. - Subscribed, ///< The sender has allowed the recipient to receive their presence. - Unsubscribe, ///< The sender is unsubscribing from another entity's presence. - Unsubscribed, ///< The subscription request has been denied or a previously-granted subscription has been cancelled. - Probe ///< A request for an entity's current presence; SHOULD be generated only by a server on behalf of a user. - }; - - // XEP-0153: vCard-Based Avatars - enum VCardUpdateType - { - VCardUpdateNone = 0, ///< Protocol is not supported - VCardUpdateNoPhoto, ///< User is not using any image - VCardUpdateValidPhoto, ///< User is advertising an image - VCardUpdateNotReady ///< User is not ready to advertise an image - -/// \note This enables recipients to distinguish between the absence of an image -/// (empty photo element) and mere support for the protocol (empty update child). - }; - - /// \brief The QXmppPresence::Status class represents the status of an XMPP entity. - /// - /// It stores information such as the "away", "busy" status of a user, or - /// a human-readable description. - - class Status - { - public: - /// This enum is used to describe an availability status. - enum Type - { - Offline = 0, - Online, ///< The entity or resource is online. - Away, ///< The entity or resource is temporarily away. - XA, ///< The entity or resource is away for an extended period. - DND, ///< The entity or resource is busy ("Do Not Disturb"). - Chat, ///< The entity or resource is actively interested in chatting. - }; - - Status(QXmppPresence::Status::Type type = QXmppPresence::Status::Online, - const QString statusText = "", int priority = 0); - - QXmppPresence::Status::Type type() const; - void setType(QXmppPresence::Status::Type); - - QString statusText() const; - void setStatusText(const QString&); - - int priority() const; - void setPriority(int); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - - private: - QString getTypeStr() const; - void setTypeFromStr(const QString&); - - QXmppPresence::Status::Type m_type; - QString m_statusText; - int m_priority; - }; - - QXmppPresence(QXmppPresence::Type type = QXmppPresence::Available, - const QXmppPresence::Status& status = QXmppPresence::Status()); - ~QXmppPresence(); - - QXmppPresence::Type type() const; - void setType(QXmppPresence::Type); - - QXmppPresence::Status& status(); - const QXmppPresence::Status& status() const; - void setStatus(const QXmppPresence::Status&); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - - // XEP-0045: Multi-User Chat - QXmppMucItem mucItem() const; - void setMucItem(const QXmppMucItem &item); - - QList mucStatusCodes() const; - void setMucStatusCodes(const QList &codes); - - /// XEP-0153: vCard-Based Avatars - QByteArray photoHash() const; - void setPhotoHash(const QByteArray&); - - VCardUpdateType vCardUpdateType() const; - void setVCardUpdateType(VCardUpdateType type); - - // XEP-0115: Entity Capabilities - QString capabilityHash() const; - void setCapabilityHash(const QString&); - - QString capabilityNode() const; - void setCapabilityNode(const QString&); - - QByteArray capabilityVer() const; - void setCapabilityVer(const QByteArray&); - - QStringList capabilityExt() const; - -private: - QString getTypeStr() const; - void setTypeFromStr(const QString&); - - Type m_type; - QXmppPresence::Status m_status; - - - /// XEP-0153: vCard-Based Avatars - - /// m_photoHash: the SHA1 hash of the avatar image data itself (not the base64-encoded version) - /// in accordance with RFC 3174 - QByteArray m_photoHash; - VCardUpdateType m_vCardUpdateType; - - // XEP-0115: Entity Capabilities - QString m_capabilityHash; - QString m_capabilityNode; - QByteArray m_capabilityVer; - // Legacy XEP-0115: Entity Capabilities - QStringList m_capabilityExt; - - // XEP-0045: Multi-User Chat - QXmppMucItem m_mucItem; - QList m_mucStatusCodes; -}; - -#endif // QXMPPPRESENCE_H diff --git a/src/QXmppPubSubIq.cpp b/src/QXmppPubSubIq.cpp deleted file mode 100644 index 1ad1c39d..00000000 --- a/src/QXmppPubSubIq.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include "QXmppConstants.h" -#include "QXmppPubSubIq.h" -#include "QXmppUtils.h" - -static const char *ns_pubsub = "http://jabber.org/protocol/pubsub"; - -static const char *pubsub_queries[] = { - "affiliations", - "default", - "items", - "publish", - "retract", - "subscribe", - "subscription", - "subscriptions", - "unsubscribe", -}; - -/// Returns the ID of the PubSub item. -/// - -QString QXmppPubSubItem::id() const -{ - return m_id; -} - -/// Sets the ID of the PubSub item. -/// -/// \param id - -void QXmppPubSubItem::setId(const QString &id) -{ - m_id = id; -} - -/// Returns the contents of the PubSub item. -/// - -QXmppElement QXmppPubSubItem::contents() const -{ - return m_contents; -} - -/// Sets the contents of the PubSub item. -/// -/// \param contents - -void QXmppPubSubItem::setContents(const QXmppElement &contents) -{ - m_contents = contents; -} - -void QXmppPubSubItem::parse(const QDomElement &element) -{ - m_id = element.attribute("id"); - m_contents = QXmppElement(element.firstChildElement()); -} - -void QXmppPubSubItem::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("item"); - helperToXmlAddAttribute(writer, "id", m_id); - m_contents.toXml(writer); - writer->writeEndElement(); -} - -/// Returns the PubSub queryType for this IQ. -/// - -QXmppPubSubIq::QueryType QXmppPubSubIq::queryType() const -{ - return m_queryType; -} - -/// Sets the PubSub queryType for this IQ. -/// -/// \param queryType - -void QXmppPubSubIq::setQueryType(QXmppPubSubIq::QueryType queryType) -{ - m_queryType = queryType; -} - -/// Returns the JID being queried. -/// - -QString QXmppPubSubIq::queryJid() const -{ - return m_queryJid; -} - -/// Sets the JID being queried. -/// -/// \param queryJid - -void QXmppPubSubIq::setQueryJid(const QString &queryJid) -{ - m_queryJid = queryJid; -} - -/// Returns the node being queried. -/// - -QString QXmppPubSubIq::queryNode() const -{ - return m_queryNode; -} - -/// Sets the node being queried. -/// -/// \param queryNode - -void QXmppPubSubIq::setQueryNode(const QString &queryNode) -{ - m_queryNode = queryNode; -} - -/// Returns the subscription ID. -/// - -QString QXmppPubSubIq::subscriptionId() const -{ - return m_subscriptionId; -} - -/// Sets the subscription ID. -/// -/// \param subscriptionId - -void QXmppPubSubIq::setSubscriptionId(const QString &subscriptionId) -{ - m_subscriptionId = subscriptionId; -} - -/// Returns the IQ's items. -/// - -QList QXmppPubSubIq::items() const -{ - return m_items; -} - -/// Sets the IQ's items. -/// -/// \param items - -void QXmppPubSubIq::setItems(const QList &items) -{ - m_items = items; -} - -bool QXmppPubSubIq::isPubSubIq(const QDomElement &element) -{ - const QDomElement pubSubElement = element.firstChildElement("pubsub"); - return pubSubElement.namespaceURI() == ns_pubsub; -} - -void QXmppPubSubIq::parseElementFromChild(const QDomElement &element) -{ - const QDomElement pubSubElement = element.firstChildElement("pubsub"); - - const QDomElement queryElement = pubSubElement.firstChildElement(); - - // determine query type - const QString tagName = queryElement.tagName(); - for (int i = ItemsQuery; i <= SubscriptionsQuery; i++) - { - if (tagName == pubsub_queries[i]) - { - m_queryType = static_cast(i); - break; - } - } - m_queryJid = queryElement.attribute("jid"); - m_queryNode = queryElement.attribute("node"); - - // parse contents - QDomElement childElement; - switch (m_queryType) - { - case QXmppPubSubIq::ItemsQuery: - case QXmppPubSubIq::PublishQuery: - childElement = queryElement.firstChildElement("item"); - while (!childElement.isNull()) - { - QXmppPubSubItem item; - item.parse(childElement); - m_items << item; - childElement = childElement.nextSiblingElement("item"); - } - break; - case QXmppPubSubIq::SubscriptionQuery: - m_subscriptionId = queryElement.attribute("subid"); - m_subscriptionType = queryElement.attribute("subscription"); - break; - default: - break; - } -} - -void QXmppPubSubIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("pubsub"); - writer->writeAttribute("xmlns", ns_pubsub); - - // write query type - writer->writeStartElement(pubsub_queries[m_queryType]); - helperToXmlAddAttribute(writer, "jid", m_queryJid); - helperToXmlAddAttribute(writer, "node", m_queryNode); - - // write contents - switch (m_queryType) - { - case QXmppPubSubIq::ItemsQuery: - case QXmppPubSubIq::PublishQuery: - foreach (const QXmppPubSubItem &item, m_items) - item.toXml(writer); - break; - case QXmppPubSubIq::SubscriptionQuery: - helperToXmlAddAttribute(writer, "subid", m_subscriptionId); - helperToXmlAddAttribute(writer, "subscription", m_subscriptionType); - break; - default: - break; - } - writer->writeEndElement(); - writer->writeEndElement(); -} diff --git a/src/QXmppPubSubIq.h b/src/QXmppPubSubIq.h deleted file mode 100644 index 01dc3a92..00000000 --- a/src/QXmppPubSubIq.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPPUBSUBIQ_H -#define QXMPPPUBSUBIQ_H - -#include "QXmppIq.h" - -/// \brief The QXmppPubSubItem class represents a publish-subscribe item -/// as defined by XEP-0060: Publish-Subscribe. -/// - -class QXmppPubSubItem -{ -public: - QString id() const; - void setId(const QString &id); - - QXmppElement contents() const; - void setContents(const QXmppElement &contents); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString m_id; - QXmppElement m_contents; -}; - -/// \brief The QXmppPubSubIq class represents an IQ used for the -/// publish-subscribe mechanisms defined by XEP-0060: Publish-Subscribe. -/// -/// \ingroup Stanzas - -class QXmppPubSubIq : public QXmppIq -{ -public: - /// This enum is used to describe a publish-subscribe query type. - enum QueryType - { - AffiliationsQuery, - DefaultQuery, - ItemsQuery, - PublishQuery, - RetractQuery, - SubscribeQuery, - SubscriptionQuery, - SubscriptionsQuery, - UnsubscribeQuery, - }; - - QXmppPubSubIq::QueryType queryType() const; - void setQueryType(QXmppPubSubIq::QueryType queryType); - - QString queryJid() const; - void setQueryJid(const QString &jid); - - QString queryNode() const; - void setQueryNode(const QString &node); - - QList items() const; - void setItems(const QList &items); - - QString subscriptionId() const; - void setSubscriptionId(const QString &id); - - /// \cond - static bool isPubSubIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement&); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QXmppPubSubIq::QueryType m_queryType; - QString m_queryJid; - QString m_queryNode; - QList m_items; - QString m_subscriptionId; - QString m_subscriptionType; -}; - -#endif diff --git a/src/QXmppRosterIq.cpp b/src/QXmppRosterIq.cpp deleted file mode 100644 index 0b2e1716..00000000 --- a/src/QXmppRosterIq.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include -#include - -#include "QXmppRosterIq.h" -#include "QXmppConstants.h" -#include "QXmppUtils.h" - -/// Adds an item to the roster IQ. -/// -/// \param item - -void QXmppRosterIq::addItem(const Item& item) -{ - m_items.append(item); -} - -/// Returns the roster IQ's items. - -QList QXmppRosterIq::items() const -{ - return m_items; -} - -bool QXmppRosterIq::isRosterIq(const QDomElement &element) -{ - return (element.firstChildElement("query").namespaceURI() == ns_roster); -} - -void QXmppRosterIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement itemElement = element. - firstChildElement("query"). - firstChildElement("item"); - while(!itemElement.isNull()) - { - QXmppRosterIq::Item item; - item.parse(itemElement); - m_items.append(item); - itemElement = itemElement.nextSiblingElement(); - } -} - -void QXmppRosterIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("query"); - writer->writeAttribute( "xmlns", ns_roster); - - for(int i = 0; i < m_items.count(); ++i) - m_items.at(i).toXml(writer); - writer->writeEndElement(); -} - -/// Returns the bareJid of the roster entry. -/// -/// \return bareJid as a QString -/// - -QString QXmppRosterIq::Item::bareJid() const -{ - return m_bareJid; -} - -/// Sets the bareJid of the roster entry. -/// -/// \param bareJid as a QString -/// - -void QXmppRosterIq::Item::setBareJid(const QString &bareJid) -{ - m_bareJid = bareJid; -} - -/// Returns the groups of the roster entry. -/// -/// \return QSet list of all the groups -/// - -QSet QXmppRosterIq::Item::groups() const -{ - return m_groups; -} - -/// Sets the groups of the roster entry. -/// -/// \param groups list of all the groups as a QSet -/// - -void QXmppRosterIq::Item::setGroups(const QSet& groups) -{ - m_groups = groups; -} - -/// Returns the name of the roster entry. -/// -/// \return name as a QString -/// - -QString QXmppRosterIq::Item::name() const -{ - return m_name; -} - -/// Sets the name of the roster entry. -/// -/// \param name as a QString -/// - -void QXmppRosterIq::Item::setName(const QString &name) -{ - m_name = name; -} - -/// Returns the subscription status of the roster entry. It is the "ask" -/// attribute in the Roster IQ stanza. Its value can be "subscribe" or "unsubscribe" -/// or empty. -/// -/// \return subscription status as a QString -/// -/// - -QString QXmppRosterIq::Item::subscriptionStatus() const -{ - return m_subscriptionStatus; -} - -/// Sets the subscription status of the roster entry. It is the "ask" -/// attribute in the Roster IQ stanza. Its value can be "subscribe" or "unsubscribe" -/// or empty. -/// -/// \param status as a QString -/// - -void QXmppRosterIq::Item::setSubscriptionStatus(const QString &status) -{ - m_subscriptionStatus = status; -} - -/// Returns the subscription type of the roster entry. -/// - -QXmppRosterIq::Item::SubscriptionType - QXmppRosterIq::Item::subscriptionType() const -{ - return m_type; -} - -/// Sets the subscription type of the roster entry. -/// -/// \param type -/// - -void QXmppRosterIq::Item::setSubscriptionType(SubscriptionType type) -{ - m_type = type; -} - -QString QXmppRosterIq::Item::getSubscriptionTypeStr() const -{ - switch(m_type) - { - case NotSet: - return ""; - case None: - return "none"; - case Both: - return "both"; - case From: - return "from"; - case To: - return "to"; - case Remove: - return "remove"; - default: - { - qWarning("QXmppRosterIq::Item::getTypeStr(): invalid type"); - return ""; - } - } -} - -void QXmppRosterIq::Item::setSubscriptionTypeFromStr(const QString& type) -{ - if(type == "") - setSubscriptionType(NotSet); - else if(type == "none") - setSubscriptionType(None); - else if(type == "both") - setSubscriptionType(Both); - else if(type == "from") - setSubscriptionType(From); - else if(type == "to") - setSubscriptionType(To); - else if(type == "remove") - setSubscriptionType(Remove); - else - qWarning("QXmppRosterIq::Item::setTypeFromStr(): invalid type"); -} - -void QXmppRosterIq::Item::parse(const QDomElement &element) -{ - m_name = element.attribute("name"); - m_bareJid = element.attribute("jid"); - setSubscriptionTypeFromStr(element.attribute("subscription")); - setSubscriptionStatus(element.attribute("ask")); - - QDomElement groupElement = element.firstChildElement("group"); - while(!groupElement.isNull()) - { - m_groups << groupElement.text(); - groupElement = groupElement.nextSiblingElement("group"); - } -} - -void QXmppRosterIq::Item::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("item"); - helperToXmlAddAttribute(writer,"jid", m_bareJid); - helperToXmlAddAttribute(writer,"name", m_name); - helperToXmlAddAttribute(writer,"subscription", getSubscriptionTypeStr()); - helperToXmlAddAttribute(writer, "ask", subscriptionStatus()); - - QSet::const_iterator i = m_groups.constBegin(); - while(i != m_groups.constEnd()) - { - helperToXmlAddTextElement(writer,"group", *i); - ++i; - } - writer->writeEndElement(); -} diff --git a/src/QXmppRosterIq.h b/src/QXmppRosterIq.h deleted file mode 100644 index 9680a176..00000000 --- a/src/QXmppRosterIq.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPROSTERIQ_H -#define QXMPPROSTERIQ_H - -#include "QXmppIq.h" -#include -#include - -/// \brief The QXmppRosterIq class represents a roster IQ. -/// -/// \ingroup Stanzas - -class QXmppRosterIq : public QXmppIq -{ -public: - - /// \brief The QXmppRosterIq::Item class represents a roster entry. - class Item - { - public: - /// An enumeration for type of subscription with the bareJid in the roster. - enum SubscriptionType - { - None = 0, ///< the user does not have a subscription to the - ///< contact's presence information, and the contact does - ///< not have a subscription to the user's presence information - From = 1, ///< the contact has a subscription to the user's presence information, - ///< but the user does not have a subscription to the contact's presence information - To = 2, ///< the user has a subscription to the contact's presence information, - ///< but the contact does not have a subscription to the user's presence information - Both = 3, ///< both the user and the contact have subscriptions to each - ///< other's presence information - Remove = 4, ///< to delete a roster item - NotSet = 8 ///< the subscription state was not specified - }; - - QString bareJid() const; - QSet groups() const; - QString name() const; - QString subscriptionStatus() const; - SubscriptionType subscriptionType() const; - - void setBareJid(const QString&); - void setGroups(const QSet&); - void setName(const QString&); - void setSubscriptionStatus(const QString&); - void setSubscriptionType(SubscriptionType); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - - private: - QString getSubscriptionTypeStr() const; - void setSubscriptionTypeFromStr(const QString&); - - QString m_bareJid; - SubscriptionType m_type; - QString m_name; - // can be subscribe/unsubscribe (attribute "ask") - QString m_subscriptionStatus; - QSet m_groups; - }; - - void addItem(const Item&); - QList items() const; - - /// \cond - static bool isRosterIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QList m_items; -}; - -#endif // QXMPPROSTERIQ_H diff --git a/src/QXmppRpcIq.cpp b/src/QXmppRpcIq.cpp deleted file mode 100644 index a2647077..00000000 --- a/src/QXmppRpcIq.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Ian Reinhart Geiser - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include -#include -#include -#include -#include - -#include "QXmppConstants.h" -#include "QXmppRpcIq.h" -#include "QXmppUtils.h" - -void XMLRPC::marshall(QXmlStreamWriter *writer, const QVariant &value) -{ - writer->writeStartElement("value"); - switch( value.type() ) - { - case QVariant::Int: - case QVariant::UInt: - case QVariant::LongLong: - case QVariant::ULongLong: - writer->writeTextElement("i4", value.toString()); - break; - case QVariant::Double: - writer->writeTextElement("double", value.toString()); - break; - case QVariant::Bool: - writer->writeTextElement("boolean", value.toBool() ? "1" : "0"); - break; - case QVariant::Date: - writer->writeTextElement("dateTime.iso8601", value.toDate().toString( Qt::ISODate ) ); - break; - case QVariant::DateTime: - writer->writeTextElement("dateTime.iso8601", value.toDateTime().toString( Qt::ISODate ) ); - break; - case QVariant::Time: - writer->writeTextElement("dateTime.iso8601", value.toTime().toString( Qt::ISODate ) ); - break; - case QVariant::StringList: - case QVariant::List: - { - writer->writeStartElement("array"); - writer->writeStartElement("data"); - foreach(const QVariant &item, value.toList()) - marshall(writer, item); - writer->writeEndElement(); - writer->writeEndElement(); - break; - } - case QVariant::Map: - { - writer->writeStartElement("struct"); - QMap map = value.toMap(); - QMap::ConstIterator index = map.begin(); - while( index != map.end() ) - { - writer->writeStartElement("member"); - writer->writeTextElement("name", index.key()); - marshall( writer, *index ); - writer->writeEndElement(); - ++index; - } - writer->writeEndElement(); - break; - } - case QVariant::ByteArray: - { - writer->writeTextElement("base64", value.toByteArray().toBase64() ); - break; - } - default: - { - if (value.isNull()) - writer->writeEmptyElement("nil"); - else if( value.canConvert(QVariant::String) ) - { - writer->writeTextElement("string", value.toString() ); - } - break; - } - } - writer->writeEndElement(); -} - -QVariant XMLRPC::demarshall(const QDomElement &elem, QStringList &errors) -{ - if ( elem.tagName().toLower() != "value" ) - { - errors << "Bad param value"; - return QVariant(); - } - - if ( !elem.firstChild().isElement() ) - { - return QVariant( elem.text() ); - } - - const QDomElement typeData = elem.firstChild().toElement(); - const QString typeName = typeData.tagName().toLower(); - - if (typeName == "nil") - { - return QVariant(); - } - if ( typeName == "string" ) - { - return QVariant( typeData.text() ); - } - else if (typeName == "int" || typeName == "i4" ) - { - bool ok = false; - QVariant val( typeData.text().toInt( &ok ) ); - if (ok) - return val; - errors << "I was looking for an integer but data was courupt"; - return QVariant(); - } - else if( typeName == "double" ) - { - bool ok = false; - QVariant val( typeData.text().toDouble( &ok ) ); - if (ok) - return val; - errors << "I was looking for an double but data was corrupt"; - } - else if( typeName == "boolean" ) - return QVariant( typeData.text() == "1" || typeData.text().toLower() == "true" ); - else if( typeName == "datetime" || typeName == "datetime.iso8601" ) - return QVariant( QDateTime::fromString( typeData.text(), Qt::ISODate ) ); - else if( typeName == "array" ) - { - QVariantList arr; - QDomElement valueNode = typeData.firstChildElement("data").firstChildElement(); - while (!valueNode.isNull() && errors.isEmpty()) - { - arr.append(demarshall(valueNode, errors)); - valueNode = valueNode.nextSiblingElement(); - } - return QVariant( arr ); - } - else if( typeName == "struct" ) - { - QMap stct; - QDomNode valueNode = typeData.firstChild(); - while(!valueNode.isNull() && errors.isEmpty()) - { - const QDomElement memberNode = valueNode.toElement().elementsByTagName("name").item(0).toElement(); - const QDomElement dataNode = valueNode.toElement().elementsByTagName("value").item(0).toElement(); - stct[ memberNode.text() ] = demarshall(dataNode, errors); - valueNode = valueNode.nextSibling(); - } - return QVariant(stct); - } - else if( typeName == "base64" ) - { - QVariant returnVariant; - QByteArray dest; - QByteArray src = typeData.text().toLatin1(); - return QVariant(QByteArray::fromBase64(src)); - } - - errors << QString( "Cannot handle type %1").arg(typeName); - return QVariant(); -} - -QXmppRpcErrorIq::QXmppRpcErrorIq() : QXmppIq( QXmppIq::Error ) -{ - -} - -QXmppRpcInvokeIq QXmppRpcErrorIq::query() const -{ - return m_query; -} - -void QXmppRpcErrorIq::setQuery(const QXmppRpcInvokeIq &query) -{ - m_query = query; -} - -bool QXmppRpcErrorIq::isRpcErrorIq(const QDomElement &element) -{ - QString type = element.attribute("type"); - QDomElement errorElement = element.firstChildElement("error"); - QDomElement queryElement = element.firstChildElement("query"); - return (type == "error") && - !errorElement.isNull() && - queryElement.namespaceURI() == ns_rpc; -} - -void QXmppRpcErrorIq::parseElementFromChild(const QDomElement &element) -{ - m_query.parseElementFromChild(element); -} - -void QXmppRpcErrorIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - m_query.toXmlElementFromChild(writer); -} - -QXmppRpcResponseIq::QXmppRpcResponseIq() - : QXmppIq(QXmppIq::Result), - m_faultCode(0) -{ -} - -/// Returns the fault code. -/// - -int QXmppRpcResponseIq::faultCode() const -{ - return m_faultCode; -} - -/// Sets the fault code. -/// -/// \param faultCode - -void QXmppRpcResponseIq::setFaultCode(int faultCode) -{ - m_faultCode = faultCode; -} - -/// Returns the fault string. -/// - -QString QXmppRpcResponseIq::faultString() const -{ - return m_faultString; -} - -/// Sets the fault string. -/// -/// \param faultString - -void QXmppRpcResponseIq::setFaultString(const QString& faultString) -{ - m_faultString = faultString; -} - -/// Returns the response values. -/// - -QVariantList QXmppRpcResponseIq::values() const -{ - return m_values; -} - -/// Sets the response values. -/// -/// \param values - -void QXmppRpcResponseIq::setValues(const QVariantList &values) -{ - m_values = values; -} - -bool QXmppRpcResponseIq::isRpcResponseIq(const QDomElement &element) -{ - QString type = element.attribute("type"); - QDomElement dataElement = element.firstChildElement("query"); - return dataElement.namespaceURI() == ns_rpc && - type == "result"; -} - -void QXmppRpcResponseIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - QDomElement methodElement = queryElement.firstChildElement("methodResponse"); - - const QDomElement contents = methodElement.firstChildElement(); - if( contents.tagName().toLower() == "params") - { - QDomNode param = contents.firstChildElement("param"); - while (!param.isNull()) - { - QStringList errors; - const QVariant value = XMLRPC::demarshall(param.firstChildElement("value"), errors); - if (!errors.isEmpty()) - break; - m_values << value; - param = param.nextSiblingElement("param"); - } - } - else if( contents.tagName().toLower() == "fault") - { - QStringList errors; - const QDomElement errElement = contents.firstChildElement("value"); - const QVariant error = XMLRPC::demarshall(errElement, errors); - if (!errors.isEmpty()) - return; - m_faultCode = error.toMap()["faultCode"].toInt(); - m_faultString = error.toMap()["faultString"].toString(); - } -} - -void QXmppRpcResponseIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("query"); - writer->writeAttribute("xmlns", ns_rpc); - - writer->writeStartElement("methodResponse"); - if (m_faultCode) - { - writer->writeStartElement("fault"); - QMap fault; - fault["faultCode"] = m_faultCode; - fault["faultString"] = m_faultString; - XMLRPC::marshall(writer, fault); - writer->writeEndElement(); - } - else if (!m_values.isEmpty()) - { - writer->writeStartElement("params"); - foreach (const QVariant &arg, m_values) - { - writer->writeStartElement("param"); - XMLRPC::marshall(writer, arg); - writer->writeEndElement(); - } - writer->writeEndElement(); - } - writer->writeEndElement(); - - writer->writeEndElement(); -} - -QXmppRpcInvokeIq::QXmppRpcInvokeIq() - : QXmppIq(QXmppIq::Set) -{ -} - -/// Returns the method arguments. -/// - -QVariantList QXmppRpcInvokeIq::arguments() const -{ - return m_arguments; -} - -/// Sets the method arguments. -/// -/// \param arguments - -void QXmppRpcInvokeIq::setArguments(const QVariantList &arguments) -{ - m_arguments = arguments; -} - -/// Returns the method name. -/// - -QString QXmppRpcInvokeIq::method() const -{ - return m_method; -} - -/// Sets the method name. -/// -/// \param method - -void QXmppRpcInvokeIq::setMethod(const QString &method) -{ - m_method = method; -} - -bool QXmppRpcInvokeIq::isRpcInvokeIq(const QDomElement &element) -{ - QString type = element.attribute("type"); - QDomElement dataElement = element.firstChildElement("query"); - return dataElement.namespaceURI() == ns_rpc && - type == "set"; -} - -void QXmppRpcInvokeIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - QDomElement methodElement = queryElement.firstChildElement("methodCall"); - - m_method = methodElement.firstChildElement("methodName").text(); - - const QDomElement methodParams = methodElement.firstChildElement("params"); - m_arguments.clear(); - if( !methodParams.isNull() ) - { - QDomNode param = methodParams.firstChildElement("param"); - while (!param.isNull()) - { - QStringList errors; - QVariant arg = XMLRPC::demarshall(param.firstChildElement("value"), errors); - if (!errors.isEmpty()) - break; - m_arguments << arg; - param = param.nextSiblingElement("param"); - } - } -} - -void QXmppRpcInvokeIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("query"); - writer->writeAttribute("xmlns", ns_rpc); - - writer->writeStartElement("methodCall"); - writer->writeTextElement("methodName", m_method); - if (!m_arguments.isEmpty()) - { - writer->writeStartElement("params"); - foreach(const QVariant &arg, m_arguments) - { - writer->writeStartElement("param"); - XMLRPC::marshall(writer, arg); - writer->writeEndElement(); - } - writer->writeEndElement(); - } - writer->writeEndElement(); - - writer->writeEndElement(); -} - diff --git a/src/QXmppRpcIq.h b/src/QXmppRpcIq.h deleted file mode 100644 index f557686a..00000000 --- a/src/QXmppRpcIq.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Ian Reinhart Geiser - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPRPCIQ_H -#define QXMPPRPCIQ_H - -#include "QXmppIq.h" -#include - -class QXmlStreamWriter; -class QDomElement; - -namespace XMLRPC -{ - void marshall( QXmlStreamWriter *writer, const QVariant &value); - QVariant demarshall(const QDomElement &elem, QStringList &errors); -} - -/// \brief The QXmppRpcResponseIq class represents an IQ used to carry -/// an RPC response as specified by XEP-0009: Jabber-RPC. -/// -/// \ingroup Stanzas - -class QXmppRpcResponseIq : public QXmppIq -{ -public: - QXmppRpcResponseIq(); - - int faultCode() const; - void setFaultCode(int faultCode); - - QString faultString() const; - void setFaultString(const QString &faultString); - - QVariantList values() const; - void setValues(const QVariantList &values); - - /// \cond - static bool isRpcResponseIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - int m_faultCode; - QString m_faultString; - QVariantList m_values; -}; - -/// \brief The QXmppRpcInvokeIq class represents an IQ used to carry -/// an RPC invocation as specified by XEP-0009: Jabber-RPC. -/// -/// \ingroup Stanzas - -class QXmppRpcInvokeIq : public QXmppIq -{ -public: - QXmppRpcInvokeIq(); - - QString method() const; - void setMethod( const QString &method ); - - QVariantList arguments() const; - void setArguments(const QVariantList &arguments); - - /// \cond - static bool isRpcInvokeIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QVariantList m_arguments; - QString m_method; - - friend class QXmppRpcErrorIq; -}; - -class QXmppRpcErrorIq : public QXmppIq -{ -public: - QXmppRpcErrorIq(); - - QXmppRpcInvokeIq query() const; - void setQuery(const QXmppRpcInvokeIq &query); - - /// \cond - static bool isRpcErrorIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QXmppRpcInvokeIq m_query; -}; - -#endif // QXMPPRPCIQ_H diff --git a/src/QXmppRtpChannel.cpp b/src/QXmppRtpChannel.cpp deleted file mode 100644 index df26bc30..00000000 --- a/src/QXmppRtpChannel.cpp +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include -#include -#include - -#include "QXmppCodec.h" -#include "QXmppJingleIq.h" -#include "QXmppRtpChannel.h" - -#ifndef M_PI -#define M_PI 3.14159265358979323846264338327950288 -#endif - -//#define QXMPP_DEBUG_RTP -//#define QXMPP_DEBUG_RTP_BUFFER -#define SAMPLE_BYTES 2 - -const quint8 RTP_VERSION = 0x02; - -/// Parses an RTP packet. -/// -/// \param ba - -bool QXmppRtpPacket::decode(const QByteArray &ba) -{ - if (ba.isEmpty()) - return false; - - // fixed header - quint8 tmp; - QDataStream stream(ba); - stream >> tmp; - version = (tmp >> 6); - const quint8 cc = (tmp >> 1) & 0xf; - const int hlen = 12 + 4 * cc; - if (version != RTP_VERSION || ba.size() < hlen) - return false; - stream >> tmp; - marker = (tmp >> 7); - type = tmp & 0x7f; - stream >> sequence; - stream >> stamp; - stream >> ssrc; - - // contributing source IDs - csrc.clear(); - quint32 src; - for (int i = 0; i < cc; ++i) { - stream >> src; - csrc << src; - } - - // retrieve payload - payload = ba.right(ba.size() - hlen); - return true; -} - -/// Encodes an RTP packet. - -QByteArray QXmppRtpPacket::encode() const -{ - Q_ASSERT(csrc.size() < 16); - - // fixed header - QByteArray ba; - ba.resize(payload.size() + 12 + 4 * csrc.size()); - QDataStream stream(&ba, QIODevice::WriteOnly); - stream << quint8(((version & 0x3) << 6) | - ((csrc.size() & 0xf) << 1)); - stream << quint8((type & 0x7f) | (marker << 7)); - stream << sequence; - stream << stamp; - stream << ssrc; - - // contributing source ids - foreach (const quint32 &src, csrc) - stream << src; - - stream.writeRawData(payload.constData(), payload.size()); - return ba; -} - -/// Returns a string representation of the RTP header. - -QString QXmppRtpPacket::toString() const -{ - return QString("RTP packet seq %1 stamp %2 marker %3 type %4 size %5").arg( - QString::number(sequence), - QString::number(stamp), - QString::number(marker), - QString::number(type), - QString::number(payload.size())); -} - -/// Creates a new RTP channel. - -QXmppRtpChannel::QXmppRtpChannel() - : m_outgoingPayloadNumbered(false) -{ -} - -/// Returns the local payload types. -/// - -QList QXmppRtpChannel::localPayloadTypes() -{ - m_outgoingPayloadNumbered = true; - return m_outgoingPayloadTypes; -} - -/// Sets the remote payload types. -/// -/// \param remotePayloadTypes - -void QXmppRtpChannel::setRemotePayloadTypes(const QList &remotePayloadTypes) -{ - QList commonOutgoingTypes; - QList commonIncomingTypes; - - foreach (const QXmppJinglePayloadType &incomingType, remotePayloadTypes) { - // check we support this payload type - int outgoingIndex = m_outgoingPayloadTypes.indexOf(incomingType); - if (outgoingIndex < 0) - continue; - QXmppJinglePayloadType outgoingType = m_outgoingPayloadTypes[outgoingIndex]; - - // be kind and try to adopt the other agent's numbering - if (!m_outgoingPayloadNumbered && outgoingType.id() > 95) { - outgoingType.setId(incomingType.id()); - } - commonIncomingTypes << incomingType; - commonOutgoingTypes << outgoingType; - } - if (commonOutgoingTypes.isEmpty()) { - qWarning("QXmppRtpChannel could not negociate a common codec"); - return; - } - m_incomingPayloadTypes = commonIncomingTypes; - m_outgoingPayloadTypes = commonOutgoingTypes; - m_outgoingPayloadNumbered = true; - - // call hook - payloadTypesChanged(); -} - -void QXmppRtpChannel::payloadTypesChanged() -{ -} - -enum CodecId { - G711u = 0, - GSM = 3, - G723 = 4, - G711a = 8, - G722 = 9, - L16Stereo = 10, - L16Mono = 11, - G728 = 15, - G729 = 18, -}; - -struct ToneInfo -{ - QXmppRtpAudioChannel::Tone tone; - quint32 incomingStart; - quint32 outgoingStart; - bool finished; -}; - -static QPair toneFreqs(QXmppRtpAudioChannel::Tone tone) -{ - switch (tone) { - case QXmppRtpAudioChannel::Tone_1: return qMakePair(697, 1209); - case QXmppRtpAudioChannel::Tone_2: return qMakePair(697, 1336); - case QXmppRtpAudioChannel::Tone_3: return qMakePair(697, 1477); - case QXmppRtpAudioChannel::Tone_A: return qMakePair(697, 1633); - case QXmppRtpAudioChannel::Tone_4: return qMakePair(770, 1209); - case QXmppRtpAudioChannel::Tone_5: return qMakePair(770, 1336); - case QXmppRtpAudioChannel::Tone_6: return qMakePair(770, 1477); - case QXmppRtpAudioChannel::Tone_B: return qMakePair(770, 1633); - case QXmppRtpAudioChannel::Tone_7: return qMakePair(852, 1209); - case QXmppRtpAudioChannel::Tone_8: return qMakePair(852, 1336); - case QXmppRtpAudioChannel::Tone_9: return qMakePair(852, 1477); - case QXmppRtpAudioChannel::Tone_C: return qMakePair(852, 1633); - case QXmppRtpAudioChannel::Tone_Star: return qMakePair(941, 1209); - case QXmppRtpAudioChannel::Tone_0: return qMakePair(941, 1336); - case QXmppRtpAudioChannel::Tone_Pound: return qMakePair(941, 1477); - case QXmppRtpAudioChannel::Tone_D: return qMakePair(941, 1633); - } - return qMakePair(0, 0); -} - -QByteArray renderTone(QXmppRtpAudioChannel::Tone tone, int clockrate, quint32 clockTick, qint64 samples) -{ - QPair tf = toneFreqs(tone); - const float clockMult = 2.0 * M_PI / float(clockrate); - QByteArray chunk; - chunk.reserve(samples * SAMPLE_BYTES); - QDataStream output(&chunk, QIODevice::WriteOnly); - output.setByteOrder(QDataStream::LittleEndian); - for (quint32 i = 0; i < samples; ++i) { - quint16 val = 16383.0 * (sin(clockMult * clockTick * tf.first) + sin(clockMult * clockTick * tf.second)); - output << val; - clockTick++; - } - return chunk; -} - -class QXmppRtpAudioChannelPrivate -{ -public: - QXmppRtpAudioChannelPrivate(QXmppRtpAudioChannel *qq); - QXmppCodec *codecForPayloadType(const QXmppJinglePayloadType &payloadType); - - // signals - bool signalsEmitted; - qint64 writtenSinceLastEmit; - - // RTP - QHostAddress remoteHost; - quint16 remotePort; - - QByteArray incomingBuffer; - bool incomingBuffering; - QMap incomingCodecs; - int incomingMinimum; - int incomingMaximum; - // position of the head of the incoming buffer, in bytes - qint64 incomingPos; - quint16 incomingSequence; - - QByteArray outgoingBuffer; - quint16 outgoingChunk; - QXmppCodec *outgoingCodec; - bool outgoingMarker; - bool outgoingPayloadNumbered; - quint16 outgoingSequence; - quint32 outgoingStamp; - QTimer *outgoingTimer; - QList outgoingTones; - QXmppJinglePayloadType outgoingTonesType; - - quint32 outgoingSsrc; - QXmppJinglePayloadType payloadType; - -private: - QXmppRtpAudioChannel *q; -}; - -QXmppRtpAudioChannelPrivate::QXmppRtpAudioChannelPrivate(QXmppRtpAudioChannel *qq) - : signalsEmitted(false), - writtenSinceLastEmit(0), - incomingBuffering(true), - incomingMinimum(0), - incomingMaximum(0), - incomingPos(0), - incomingSequence(0), - outgoingCodec(0), - outgoingMarker(true), - outgoingPayloadNumbered(false), - outgoingSequence(1), - outgoingStamp(0), - outgoingSsrc(0), - q(qq) -{ - qRegisterMetaType("QXmppRtpAudioChannel::Tone"); - outgoingSsrc = qrand(); -} - -/// Returns the audio codec for the given payload type. -/// - -QXmppCodec *QXmppRtpAudioChannelPrivate::codecForPayloadType(const QXmppJinglePayloadType &payloadType) -{ - if (payloadType.id() == G711u) - return new QXmppG711uCodec(payloadType.clockrate()); - else if (payloadType.id() == G711a) - return new QXmppG711aCodec(payloadType.clockrate()); -#ifdef QXMPP_USE_SPEEX - else if (payloadType.name().toLower() == "speex") - return new QXmppSpeexCodec(payloadType.clockrate()); -#endif - return 0; -} - -/// Creates a new RTP audio channel. -/// -/// \param parent - -QXmppRtpAudioChannel::QXmppRtpAudioChannel(QObject *parent) - : QIODevice(parent) -{ - d = new QXmppRtpAudioChannelPrivate(this); - QXmppLoggable *logParent = qobject_cast(parent); - if (logParent) { - connect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), - logParent, SIGNAL(logMessage(QXmppLogger::MessageType,QString))); - } - d->outgoingTimer = new QTimer(this); - connect(d->outgoingTimer, SIGNAL(timeout()), this, SLOT(writeDatagram())); - - // set supported codecs - QXmppJinglePayloadType payload; - -#ifdef QXMPP_USE_SPEEX - payload.setId(96); - payload.setChannels(1); - payload.setName("speex"); - payload.setClockrate(8000); - m_outgoingPayloadTypes << payload; -#endif - - payload.setId(G711u); - payload.setChannels(1); - payload.setName("PCMU"); - payload.setClockrate(8000); - m_outgoingPayloadTypes << payload; - - payload.setId(G711a); - payload.setChannels(1); - payload.setName("PCMA"); - payload.setClockrate(8000); - m_outgoingPayloadTypes << payload; - - QMap parameters; - parameters.insert("events", "0-15"); - payload.setId(101); - payload.setChannels(1); - payload.setName("telephone-event"); - payload.setClockrate(8000); - payload.setParameters(parameters); - m_outgoingPayloadTypes << payload; -} - -/// Destroys an RTP audio channel. -/// - -QXmppRtpAudioChannel::~QXmppRtpAudioChannel() -{ - foreach (QXmppCodec *codec, d->incomingCodecs) - delete codec; - if (d->outgoingCodec) - delete d->outgoingCodec; - delete d; -} - -/// Returns the number of bytes that are available for reading. -/// - -qint64 QXmppRtpAudioChannel::bytesAvailable() const -{ - return d->incomingBuffer.size(); -} - -/// Closes the RTP channel. -/// - -void QXmppRtpAudioChannel::close() -{ - d->outgoingTimer->stop(); - QIODevice::close(); -} - -/// Processes an incoming RTP packet. -/// -/// \param ba - -void QXmppRtpAudioChannel::datagramReceived(const QByteArray &ba) -{ - QXmppRtpPacket packet; - if (!packet.decode(ba)) - return; - -#ifdef QXMPP_DEBUG_RTP - logReceived(packet.toString()); -#endif - - // check sequence number -#if 0 - if (d->incomingSequence && packet.sequence != d->incomingSequence + 1) - warning(QString("RTP packet seq %1 is out of order, previous was %2") - .arg(QString::number(packet.sequence)) - .arg(QString::number(d->incomingSequence))); -#endif - d->incomingSequence = packet.sequence; - - // get or create codec - QXmppCodec *codec = 0; - if (!d->incomingCodecs.contains(packet.type)) { - foreach (const QXmppJinglePayloadType &payload, m_incomingPayloadTypes) { - if (packet.type == payload.id()) { - codec = d->codecForPayloadType(payload); - break; - } - } - if (codec) - d->incomingCodecs.insert(packet.type, codec); - else - warning(QString("Could not find codec for RTP type %1").arg(QString::number(packet.type))); - } else { - codec = d->incomingCodecs.value(packet.type); - } - if (!codec) - return; - - // determine packet's position in the buffer (in bytes) - qint64 packetOffset = 0; - if (!d->incomingBuffer.isEmpty()) { - packetOffset = packet.stamp * SAMPLE_BYTES - d->incomingPos; - if (packetOffset < 0) { -#ifdef QXMPP_DEBUG_RTP_BUFFER - warning(QString("RTP packet stamp %1 is too old, buffer start is %2") - .arg(QString::number(packet.stamp)) - .arg(QString::number(d->incomingPos))); -#endif - return; - } - } else { - d->incomingPos = packet.stamp * SAMPLE_BYTES + (d->incomingPos % SAMPLE_BYTES); - } - - // allocate space for new packet - // FIXME: this is wrong, we want the decoded data size! - qint64 packetLength = packet.payload.size(); - if (packetOffset + packetLength > d->incomingBuffer.size()) - d->incomingBuffer += QByteArray(packetOffset + packetLength - d->incomingBuffer.size(), 0); - QDataStream input(packet.payload); - QDataStream output(&d->incomingBuffer, QIODevice::WriteOnly); - output.device()->seek(packetOffset); - output.setByteOrder(QDataStream::LittleEndian); - codec->decode(input, output); - - // check whether we are running late - if (d->incomingBuffer.size() > d->incomingMaximum) - { - qint64 droppedSize = d->incomingBuffer.size() - d->incomingMinimum; - const int remainder = droppedSize % SAMPLE_BYTES; - if (remainder) - droppedSize -= remainder; -#ifdef QXMPP_DEBUG_RTP_BUFFER - warning(QString("Incoming RTP buffer is too full, dropping %1 bytes") - .arg(QString::number(droppedSize))); -#endif - d->incomingBuffer.remove(0, droppedSize); - d->incomingPos += droppedSize; - } - // check whether we have filled the initial buffer - if (d->incomingBuffer.size() >= d->incomingMinimum) - d->incomingBuffering = false; - if (!d->incomingBuffering) - emit readyRead(); -} - -void QXmppRtpAudioChannel::emitSignals() -{ - emit bytesWritten(d->writtenSinceLastEmit); - d->writtenSinceLastEmit = 0; - d->signalsEmitted = false; -} - -/// Returns true, as the RTP channel is a sequential device. -/// - -bool QXmppRtpAudioChannel::isSequential() const -{ - return true; -} - -QIODevice::OpenMode QXmppRtpAudioChannel::openMode() const -{ - return QIODevice::openMode(); -} - -qint64 QXmppRtpAudioChannel::readData(char * data, qint64 maxSize) -{ - // if we are filling the buffer, return empty samples - if (d->incomingBuffering) - { - // FIXME: if we are asked for a non-integer number of samples, - // we will return junk on next read as we don't increment d->incomingPos - memset(data, 0, maxSize); - return maxSize; - } - - qint64 readSize = qMin(maxSize, qint64(d->incomingBuffer.size())); - memcpy(data, d->incomingBuffer.constData(), readSize); - d->incomingBuffer.remove(0, readSize); - if (readSize < maxSize) - { -#ifdef QXMPP_DEBUG_RTP - debug(QString("QXmppRtpAudioChannel::readData missing %1 bytes").arg(QString::number(maxSize - readSize))); -#endif - memset(data + readSize, 0, maxSize - readSize); - } - - // add local DTMF echo - if (!d->outgoingTones.isEmpty()) { - const int headOffset = d->incomingPos % SAMPLE_BYTES; - const int samples = (headOffset + maxSize + SAMPLE_BYTES - 1) / SAMPLE_BYTES; - const QByteArray chunk = renderTone( - d->outgoingTones[0].tone, - d->payloadType.clockrate(), - d->incomingPos / SAMPLE_BYTES - d->outgoingTones[0].incomingStart, - samples); - memcpy(data, chunk.constData() + headOffset, maxSize); - } - - d->incomingPos += maxSize; - return maxSize; -} - -/// Returns the RTP channel's payload type. -/// -/// You can use this to determine the QAudioFormat to use with your -/// QAudioInput/QAudioOutput. - -QXmppJinglePayloadType QXmppRtpAudioChannel::payloadType() const -{ - return d->payloadType; -} - -void QXmppRtpAudioChannel::payloadTypesChanged() -{ - // delete incoming codecs - foreach (QXmppCodec *codec, d->incomingCodecs) - delete codec; - d->incomingCodecs.clear(); - - // delete outgoing codec - if (d->outgoingCodec) { - delete d->outgoingCodec; - d->outgoingCodec = 0; - } - - // create outgoing codec - foreach (const QXmppJinglePayloadType &outgoingType, m_outgoingPayloadTypes) { - // check for telephony events - if (outgoingType.name() == "telephone-event") { - d->outgoingTonesType = outgoingType; - } - else if (!d->outgoingCodec) { - QXmppCodec *codec = d->codecForPayloadType(outgoingType); - if (codec) { - d->payloadType = outgoingType; - d->outgoingCodec = codec; - } - } - } - - // size in bytes of an decoded packet - d->outgoingChunk = SAMPLE_BYTES * d->payloadType.ptime() * d->payloadType.clockrate() / 1000; - d->outgoingTimer->setInterval(d->payloadType.ptime()); - - d->incomingMinimum = d->outgoingChunk * 5; - d->incomingMaximum = d->outgoingChunk * 15; - - open(QIODevice::ReadWrite | QIODevice::Unbuffered); -} - -/// Returns the position in the received audio data. - -qint64 QXmppRtpAudioChannel::pos() const -{ - return d->incomingPos; -} - -/// Seeks in the received audio data. -/// -/// Seeking backwards will result in empty samples being added at the start -/// of the buffer. -/// -/// \param pos - -bool QXmppRtpAudioChannel::seek(qint64 pos) -{ - qint64 delta = pos - d->incomingPos; - if (delta < 0) - d->incomingBuffer.prepend(QByteArray(-delta, 0)); - else - d->incomingBuffer.remove(0, delta); - d->incomingPos = pos; - return true; -} - -/// Starts sending the specified DTMF tone. -/// -/// \param tone - -void QXmppRtpAudioChannel::startTone(QXmppRtpAudioChannel::Tone tone) -{ - ToneInfo info; - info.tone = tone; - info.incomingStart = d->incomingPos / SAMPLE_BYTES; - info.outgoingStart = d->outgoingStamp; - info.finished = false; - d->outgoingTones << info; -} - -/// Stops sending the specified DTMF tone. -/// -/// \param tone - -void QXmppRtpAudioChannel::stopTone(QXmppRtpAudioChannel::Tone tone) -{ - for (int i = 0; i < d->outgoingTones.size(); ++i) { - if (d->outgoingTones[i].tone == tone) { - d->outgoingTones[i].finished = true; - break; - } - } -} - -qint64 QXmppRtpAudioChannel::writeData(const char * data, qint64 maxSize) -{ - if (!d->outgoingCodec) { - warning("QXmppRtpAudioChannel::writeData before codec was set"); - return -1; - } - - d->outgoingBuffer += QByteArray::fromRawData(data, maxSize); - - // start sending audio chunks - if (!d->outgoingTimer->isActive()) - d->outgoingTimer->start(); - - return maxSize; -} - -void QXmppRtpAudioChannel::writeDatagram() -{ - // read audio chunk - QByteArray chunk; - if (d->outgoingBuffer.size() < d->outgoingChunk) { -#ifdef QXMPP_DEBUG_RTP_BUFFER - warning("Outgoing RTP buffer is starved"); -#endif - chunk = QByteArray(d->outgoingChunk, 0); - } else { - chunk = d->outgoingBuffer.left(d->outgoingChunk); - d->outgoingBuffer.remove(0, d->outgoingChunk); - } - - bool sendAudio = true; - if (!d->outgoingTones.isEmpty()) { - const quint32 packetTicks = (d->payloadType.clockrate() * d->payloadType.ptime()) / 1000; - const ToneInfo info = d->outgoingTones[0]; - - if (d->outgoingTonesType.id()) { - // send RFC 2833 DTMF - QXmppRtpPacket packet; - packet.version = RTP_VERSION; - packet.marker = (info.outgoingStart == d->outgoingStamp); - packet.type = d->outgoingTonesType.id(); - packet.sequence = d->outgoingSequence; - packet.stamp = info.outgoingStart; - packet.ssrc = d->outgoingSsrc; - - QDataStream output(&packet.payload, QIODevice::WriteOnly); - output << quint8(info.tone); - output << quint8(info.finished ? 0x80 : 0x00); - output << quint16(d->outgoingStamp + packetTicks - info.outgoingStart); -#ifdef QXMPP_DEBUG_RTP - logSent(packet.toString()); -#endif - emit sendDatagram(packet.encode()); - d->outgoingSequence++; - d->outgoingStamp += packetTicks; - - sendAudio = false; - } else { - // generate in-band DTMF - chunk = renderTone(info.tone, d->payloadType.clockrate(), d->outgoingStamp - info.outgoingStart, packetTicks); - } - - // if the tone is finished, remove it - if (info.finished) - d->outgoingTones.removeFirst(); - } - - if (sendAudio) { - // send audio data - QXmppRtpPacket packet; - packet.version = RTP_VERSION; - if (d->outgoingMarker) - { - packet.marker = true; - d->outgoingMarker = false; - } else { - packet.marker = false; - } - packet.type = d->payloadType.id(); - packet.sequence = d->outgoingSequence; - packet.stamp = d->outgoingStamp; - packet.ssrc = d->outgoingSsrc; - - // encode audio chunk - QDataStream input(chunk); - input.setByteOrder(QDataStream::LittleEndian); - QDataStream output(&packet.payload, QIODevice::WriteOnly); - const qint64 packetTicks = d->outgoingCodec->encode(input, output); - -#ifdef QXMPP_DEBUG_RTP - logSent(packet.toString()); -#endif - emit sendDatagram(packet.encode()); - d->outgoingSequence++; - d->outgoingStamp += packetTicks; - } - - // queue signals - d->writtenSinceLastEmit += chunk.size(); - if (!d->signalsEmitted && !signalsBlocked()) { - d->signalsEmitted = true; - QMetaObject::invokeMethod(this, "emitSignals", Qt::QueuedConnection); - } -} - -/** Constructs a null video frame. - */ -QXmppVideoFrame::QXmppVideoFrame() - : m_bytesPerLine(0), - m_height(0), - m_mappedBytes(0), - m_pixelFormat(Format_Invalid), - m_width(0) -{ -} - -/** Constructs a video frame of the given pixel format and size in pixels. - * - * @param bytes - * @param size - * @param bytesPerLine - * @param format - */ -QXmppVideoFrame::QXmppVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format) - : m_bytesPerLine(bytesPerLine), - m_height(size.height()), - m_mappedBytes(bytes), - m_pixelFormat(format), - m_width(size.width()) -{ - m_data.resize(bytes); -} - -uchar *QXmppVideoFrame::bits() -{ - return (uchar*)m_data.data(); -} - -const uchar *QXmppVideoFrame::bits() const -{ - return (const uchar*)m_data.constData(); -} - -/** Returns the number of bytes in a scan line. - */ -int QXmppVideoFrame::bytesPerLine() const -{ - return m_bytesPerLine; -} - -/** Returns the height of a video frame. - */ -int QXmppVideoFrame::height() const -{ - return m_height; -} - -/** Returns true if the frame is valid. - */ -bool QXmppVideoFrame::isValid() const -{ - return m_pixelFormat != Format_Invalid && - m_height > 0 && m_width > 0 && - m_mappedBytes > 0; -} - -/** Returns the number of bytes occupied by the mapped frame data. - */ -int QXmppVideoFrame::mappedBytes() const -{ - return m_mappedBytes; -} - -/** Returns the color format of a video frame. - */ -QXmppVideoFrame::PixelFormat QXmppVideoFrame::pixelFormat() const -{ - return m_pixelFormat; -} - -/** Returns the size of a video frame. - */ -QSize QXmppVideoFrame::size() const -{ - return QSize(m_width, m_height); -} - -/** Returns the width of a video frame. - */ -int QXmppVideoFrame::width() const -{ - return m_width; -} - -class QXmppRtpVideoChannelPrivate -{ -public: - QXmppRtpVideoChannelPrivate(); - QMap decoders; - QXmppVideoEncoder *encoder; - QList frames; - - // local - QXmppVideoFormat outgoingFormat; - quint8 outgoingId; - quint16 outgoingSequence; - quint32 outgoingStamp; - quint32 outgoingSsrc; -}; - -QXmppRtpVideoChannelPrivate::QXmppRtpVideoChannelPrivate() - : encoder(0), - outgoingId(0), - outgoingSequence(1), - outgoingStamp(0), - outgoingSsrc(0) -{ - outgoingSsrc = qrand(); -} - -QXmppRtpVideoChannel::QXmppRtpVideoChannel(QObject *parent) - : QXmppLoggable(parent) -{ - d = new QXmppRtpVideoChannelPrivate; - d->outgoingFormat.setFrameRate(15.0); - d->outgoingFormat.setFrameSize(QSize(320, 240)); - d->outgoingFormat.setPixelFormat(QXmppVideoFrame::Format_YUYV); - - // set supported codecs - QXmppVideoEncoder *encoder; - QXmppJinglePayloadType payload; - Q_UNUSED(encoder); - Q_UNUSED(payload); - -#ifdef QXMPP_USE_VPX - encoder = new QXmppVpxEncoder; - encoder->setFormat(d->outgoingFormat); - payload.setId(96); - payload.setName("vp8"); - payload.setClockrate(90000); - payload.setParameters(encoder->parameters()); - m_outgoingPayloadTypes << payload; - delete encoder; -#endif - -#ifdef QXMPP_USE_THEORA - encoder = new QXmppTheoraEncoder; - encoder->setFormat(d->outgoingFormat); - payload.setId(97); - payload.setName("theora"); - payload.setClockrate(90000); - payload.setParameters(encoder->parameters()); - m_outgoingPayloadTypes << payload; - delete encoder; -#endif -} - -QXmppRtpVideoChannel::~QXmppRtpVideoChannel() -{ - foreach (QXmppVideoDecoder *decoder, d->decoders) - delete decoder; - if (d->encoder) - delete d->encoder; - delete d; -} - -/// Closes the RTP channel. -/// - -void QXmppRtpVideoChannel::close() -{ -} - -/// Processes an incoming RTP video packet. -/// -/// \param ba - -void QXmppRtpVideoChannel::datagramReceived(const QByteArray &ba) -{ - QXmppRtpPacket packet; - if (!packet.decode(ba)) - return; - -#ifdef QXMPP_DEBUG_RTP - logReceived(packet.toString()); -#endif - - // get codec - QXmppVideoDecoder *decoder = d->decoders.value(packet.type); - if (!decoder) - return; - d->frames << decoder->handlePacket(packet); -} - -QXmppVideoFormat QXmppRtpVideoChannel::decoderFormat() const -{ - if (d->decoders.isEmpty()) - return QXmppVideoFormat(); - const int key = d->decoders.keys().first(); - return d->decoders.value(key)->format(); -} - -QXmppVideoFormat QXmppRtpVideoChannel::encoderFormat() const -{ - return d->outgoingFormat; -} - -void QXmppRtpVideoChannel::setEncoderFormat(const QXmppVideoFormat &format) -{ - if (d->encoder && !d->encoder->setFormat(format)) - return; - d->outgoingFormat = format; -} - -QIODevice::OpenMode QXmppRtpVideoChannel::openMode() const -{ - QIODevice::OpenMode mode = QIODevice::NotOpen; - if (!d->decoders.isEmpty()) - mode |= QIODevice::ReadOnly; - if (d->encoder) - mode |= QIODevice::WriteOnly; - return mode; -} - -void QXmppRtpVideoChannel::payloadTypesChanged() -{ - // refresh decoders - foreach (QXmppVideoDecoder *decoder, d->decoders) - delete decoder; - d->decoders.clear(); - foreach (const QXmppJinglePayloadType &payload, m_incomingPayloadTypes) { - QXmppVideoDecoder *decoder = 0; - if (false) - {} -#ifdef QXMPP_USE_THEORA - else if (payload.name().toLower() == "theora") - decoder = new QXmppTheoraDecoder; -#endif -#ifdef QXMPP_USE_VPX - else if (payload.name().toLower() == "vp8") - decoder = new QXmppVpxDecoder; -#endif - if (decoder) { - decoder->setParameters(payload.parameters()); - d->decoders.insert(payload.id(), decoder); - } - } - - // refresh encoder - if (d->encoder) { - delete d->encoder; - d->encoder = 0; - } - foreach (const QXmppJinglePayloadType &payload, m_outgoingPayloadTypes) { - QXmppVideoEncoder *encoder = 0; - if (false) - {} -#ifdef QXMPP_USE_THEORA - else if (payload.name().toLower() == "theora") - encoder = new QXmppTheoraEncoder; -#endif -#ifdef QXMPP_USE_VPX - else if (payload.name().toLower() == "vp8") { - encoder = new QXmppVpxEncoder; - } -#endif - if (encoder) { - encoder->setFormat(d->outgoingFormat); - d->encoder = encoder; - d->outgoingId = payload.id(); - break; - } - } -} - -QList QXmppRtpVideoChannel::readFrames() -{ - const QList frames = d->frames; - d->frames.clear(); - return frames; -} - -void QXmppRtpVideoChannel::writeFrame(const QXmppVideoFrame &frame) -{ - if (!d->encoder) { - warning("QXmppRtpVideoChannel::writeFrame before codec was set"); - return; - } - - QXmppRtpPacket packet; - packet.version = RTP_VERSION; - packet.marker = false; - packet.type = d->outgoingId; - packet.ssrc = d->outgoingSsrc; - foreach (const QByteArray &payload, d->encoder->handleFrame(frame)) { - packet.sequence = d->outgoingSequence++; - packet.stamp = d->outgoingStamp; - packet.payload = payload; -#ifdef QXMPP_DEBUG_RTP - logSent(packet.toString()); -#endif - emit sendDatagram(packet.encode()); - } - d->outgoingStamp += 1; -} - diff --git a/src/QXmppRtpChannel.h b/src/QXmppRtpChannel.h deleted file mode 100644 index 0af6596c..00000000 --- a/src/QXmppRtpChannel.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPRTPCHANNEL_H -#define QXMPPRTPCHANNEL_H - -#include -#include - -#include "QXmppJingleIq.h" -#include "QXmppLogger.h" - -class QXmppCodec; -class QXmppJinglePayloadType; -class QXmppRtpAudioChannelPrivate; -class QXmppRtpVideoChannelPrivate; - -/// \brief The QXmppRtpPacket class represents an RTP packet. -/// - -class QXmppRtpPacket -{ -public: - bool decode(const QByteArray &ba); - QByteArray encode() const; - QString toString() const; - - quint8 version; - bool marker; - quint8 type; - quint32 ssrc; - QList csrc; - quint16 sequence; - quint32 stamp; - QByteArray payload; -}; - -class QXmppRtpChannel -{ -public: - QXmppRtpChannel(); - - virtual void close() = 0; - virtual QIODevice::OpenMode openMode() const = 0; - QList localPayloadTypes(); - void setRemotePayloadTypes(const QList &remotePayloadTypes); - -protected: - virtual void payloadTypesChanged(); - - QList m_incomingPayloadTypes; - QList m_outgoingPayloadTypes; - bool m_outgoingPayloadNumbered; -}; - -/// \brief The QXmppRtpAudioChannel class represents an RTP audio channel to a remote party. -/// -/// It acts as a QIODevice so that you can read / write audio samples, for -/// instance using a QAudioOutput and a QAudioInput. -/// -/// \note THIS API IS NOT FINALIZED YET - -class QXmppRtpAudioChannel : public QIODevice, public QXmppRtpChannel -{ - Q_OBJECT - Q_ENUMS(Tone) - -public: - /// This enum is used to describe a DTMF tone. - enum Tone { - Tone_0 = 0, ///< Tone for the 0 key. - Tone_1, ///< Tone for the 1 key. - Tone_2, ///< Tone for the 2 key. - Tone_3, ///< Tone for the 3 key. - Tone_4, ///< Tone for the 4 key. - Tone_5, ///< Tone for the 5 key. - Tone_6, ///< Tone for the 6 key. - Tone_7, ///< Tone for the 7 key. - Tone_8, ///< Tone for the 8 key. - Tone_9, ///< Tone for the 9 key. - Tone_Star, ///< Tone for the * key. - Tone_Pound, ///< Tone for the # key. - Tone_A, ///< Tone for the A key. - Tone_B, ///< Tone for the B key. - Tone_C, ///< Tone for the C key. - Tone_D ///< Tone for the D key. - }; - - QXmppRtpAudioChannel(QObject *parent = 0); - ~QXmppRtpAudioChannel(); - - QXmppJinglePayloadType payloadType() const; - - /// \cond - qint64 bytesAvailable() const; - void close(); - bool isSequential() const; - QIODevice::OpenMode openMode() const; - qint64 pos() const; - bool seek(qint64 pos); - /// \endcond - -signals: - /// \brief This signal is emitted when a datagram needs to be sent. - void sendDatagram(const QByteArray &ba); - - /// \brief This signal is emitted to send logging messages. - void logMessage(QXmppLogger::MessageType type, const QString &msg); - -public slots: - void datagramReceived(const QByteArray &ba); - void startTone(QXmppRtpAudioChannel::Tone tone); - void stopTone(QXmppRtpAudioChannel::Tone tone); - -protected: - /// \cond - void debug(const QString &message) - { - emit logMessage(QXmppLogger::DebugMessage, qxmpp_loggable_trace(message)); - } - - void warning(const QString &message) - { - emit logMessage(QXmppLogger::WarningMessage, qxmpp_loggable_trace(message)); - } - - void logReceived(const QString &message) - { - emit logMessage(QXmppLogger::ReceivedMessage, qxmpp_loggable_trace(message)); - } - - void logSent(const QString &message) - { - emit logMessage(QXmppLogger::SentMessage, qxmpp_loggable_trace(message)); - } - - void payloadTypesChanged(); - qint64 readData(char * data, qint64 maxSize); - qint64 writeData(const char * data, qint64 maxSize); - /// \endcond - -private slots: - void emitSignals(); - void writeDatagram(); - -private: - friend class QXmppRtpAudioChannelPrivate; - QXmppRtpAudioChannelPrivate * d; -}; - -/// \brief The QXmppVideoFrame class provides a representation of a frame of video data. -/// -/// \note THIS API IS NOT FINALIZED YET - -class QXmppVideoFrame -{ -public: - enum PixelFormat { - Format_Invalid = 0, - Format_RGB32 = 3, - Format_RGB24 = 4, - Format_YUV420P = 18, - Format_UYVY = 20, - Format_YUYV = 21, - }; - - QXmppVideoFrame(); - QXmppVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format); - uchar *bits(); - const uchar *bits() const; - int bytesPerLine() const; - int height() const; - bool isValid() const; - int mappedBytes() const; - PixelFormat pixelFormat() const; - QSize size() const; - int width() const; - -private: - int m_bytesPerLine; - QByteArray m_data; - int m_height; - int m_mappedBytes; - PixelFormat m_pixelFormat; - int m_width; -}; - -class QXmppVideoFormat -{ -public: - int frameHeight() const { - return m_frameSize.height(); - } - - int frameWidth() const { - return m_frameSize.width(); - } - - qreal frameRate() const { - return m_frameRate; - } - - void setFrameRate(qreal frameRate) { - m_frameRate = frameRate; - } - - QSize frameSize() const { - return m_frameSize; - } - - void setFrameSize(const QSize &frameSize) { - m_frameSize = frameSize; - } - - QXmppVideoFrame::PixelFormat pixelFormat() const { - return m_pixelFormat; - } - - void setPixelFormat(QXmppVideoFrame::PixelFormat pixelFormat) { - m_pixelFormat = pixelFormat; - } - -private: - qreal m_frameRate; - QSize m_frameSize; - QXmppVideoFrame::PixelFormat m_pixelFormat; -}; - - -/// \brief The QXmppRtpVideoChannel class represents an RTP video channel to a remote party. -/// -/// \note THIS API IS NOT FINALIZED YET - -class QXmppRtpVideoChannel : public QXmppLoggable, public QXmppRtpChannel -{ - Q_OBJECT - -public: - QXmppRtpVideoChannel(QObject *parent = 0); - ~QXmppRtpVideoChannel(); - - // incoming stream - QXmppVideoFormat decoderFormat() const; - QList readFrames(); - - // outgoing stream - QXmppVideoFormat encoderFormat() const; - void setEncoderFormat(const QXmppVideoFormat &format); - void writeFrame(const QXmppVideoFrame &frame); - - QIODevice::OpenMode openMode() const; - void close(); - -signals: - /// \brief This signal is emitted when a datagram needs to be sent. - void sendDatagram(const QByteArray &ba); - -public slots: - void datagramReceived(const QByteArray &ba); - -protected: - void payloadTypesChanged(); - -private: - friend class QXmppRtpVideoChannelPrivate; - QXmppRtpVideoChannelPrivate * d; -}; - -#endif diff --git a/src/QXmppSaslAuth.cpp b/src/QXmppSaslAuth.cpp deleted file mode 100644 index a528cd6d..00000000 --- a/src/QXmppSaslAuth.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include - -#include "QXmppSaslAuth.h" -#include "QXmppUtils.h" - -QByteArray QXmppSaslDigestMd5::authzid() const -{ - return m_authzid; -} - -void QXmppSaslDigestMd5::setAuthzid(const QByteArray &authzid) -{ - m_authzid = authzid; -} - -QByteArray QXmppSaslDigestMd5::cnonce() const -{ - return m_cnonce; -} - -void QXmppSaslDigestMd5::setCnonce(const QByteArray &cnonce) -{ - m_cnonce = cnonce; -} - -QByteArray QXmppSaslDigestMd5::digestUri() const -{ - return m_digestUri; -} - -void QXmppSaslDigestMd5::setDigestUri(const QByteArray &digestUri) -{ - m_digestUri = digestUri; -} - -QByteArray QXmppSaslDigestMd5::nc() const -{ - return m_nc; -} - -void QXmppSaslDigestMd5::setNc(const QByteArray &nc) -{ - m_nc = nc; -} - -QByteArray QXmppSaslDigestMd5::nonce() const -{ - return m_nonce; -} - -void QXmppSaslDigestMd5::setNonce(const QByteArray &nonce) -{ - m_nonce = nonce; -} - -QByteArray QXmppSaslDigestMd5::qop() const -{ - return m_qop; -} - -void QXmppSaslDigestMd5::setQop(const QByteArray &qop) -{ - m_qop = qop; -} - -void QXmppSaslDigestMd5::setSecret(const QByteArray &secret) -{ - m_secret = secret; -} - -QByteArray QXmppSaslDigestMd5::generateNonce() -{ - QByteArray nonce = generateRandomBytes(32); - - // The random data can the '=' char is not valid as it is a delimiter, - // so to be safe, base64 the nonce - return nonce.toBase64(); -} - -/// Calculate digest response for use with XMPP/SASL. -/// -/// \param A2 -/// - -QByteArray QXmppSaslDigestMd5::calculateDigest(const QByteArray &A2) const -{ - QByteArray ha1 = m_secret + ':' + m_nonce + ':' + m_cnonce; - - if (!m_authzid.isEmpty()) - ha1 += ':' + m_authzid; - - return calculateDigest(ha1, A2); -} - -/// Calculate generic digest response. -/// -/// \param A1 -/// \param A2 -/// - -QByteArray QXmppSaslDigestMd5::calculateDigest(const QByteArray &A1, const QByteArray &A2) const -{ - QByteArray HA1 = QCryptographicHash::hash(A1, QCryptographicHash::Md5).toHex(); - QByteArray HA2 = QCryptographicHash::hash(A2, QCryptographicHash::Md5).toHex(); - QByteArray KD; - if (m_qop == "auth" || m_qop == "auth-int") - KD = HA1 + ':' + m_nonce + ':' + m_nc + ':' + m_cnonce + ':' + m_qop + ':' + HA2; - else - KD = HA1 + ':' + m_nonce + ':' + HA2; - return QCryptographicHash::hash(KD, QCryptographicHash::Md5).toHex(); -} - -QMap QXmppSaslDigestMd5::parseMessage(const QByteArray &ba) -{ - QMap map; - int startIndex = 0; - int pos = 0; - while ((pos = ba.indexOf("=", startIndex)) >= 0) - { - // key get name and skip equals - const QByteArray key = ba.mid(startIndex, pos - startIndex).trimmed(); - pos++; - - // check whether string is quoted - if (ba.at(pos) == '"') - { - // skip opening quote - pos++; - int endPos = ba.indexOf('"', pos); - // skip quoted quotes - while (endPos >= 0 && ba.at(endPos - 1) == '\\') - endPos = ba.indexOf('"', endPos + 1); - if (endPos < 0) - { - qWarning("Unfinished quoted string"); - return map; - } - // unquote - QByteArray value = ba.mid(pos, endPos - pos); - value.replace("\\\"", "\""); - value.replace("\\\\", "\\"); - map[key] = value; - // skip closing quote and comma - startIndex = endPos + 2; - } else { - // non-quoted string - int endPos = ba.indexOf(',', pos); - if (endPos < 0) - endPos = ba.size(); - map[key] = ba.mid(pos, endPos - pos); - // skip comma - startIndex = endPos + 1; - } - } - return map; -} - -QByteArray QXmppSaslDigestMd5::serializeMessage(const QMap &map) -{ - QByteArray ba; - foreach (const QByteArray &key, map.keys()) - { - if (!ba.isEmpty()) - ba.append(','); - ba.append(key + "="); - QByteArray value = map[key]; - const char *separators = "()<>@,;:\\\"/[]?={} \t"; - bool quote = false; - for (const char *c = separators; *c; c++) - { - if (value.contains(*c)) - { - quote = true; - break; - } - } - if (quote) - { - value.replace("\\", "\\\\"); - value.replace("\"", "\\\""); - ba.append("\"" + value + "\""); - } - else - ba.append(value); - } - return ba; -} - diff --git a/src/QXmppSaslAuth.h b/src/QXmppSaslAuth.h deleted file mode 100644 index 409636cb..00000000 --- a/src/QXmppSaslAuth.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPSASLAUTH_H -#define QXMPPSASLAUTH_H - -#include -#include - -class QXmppSaslDigestMd5 -{ -public: - QByteArray authzid() const; - void setAuthzid(const QByteArray &cnonce); - - QByteArray cnonce() const; - void setCnonce(const QByteArray &cnonce); - - QByteArray digestUri() const; - void setDigestUri(const QByteArray &digestUri); - - QByteArray nc() const; - void setNc(const QByteArray &nc); - - QByteArray nonce() const; - void setNonce(const QByteArray &nonce); - - QByteArray qop() const; - void setQop(const QByteArray &qop); - - void setSecret(const QByteArray &secret); - - QByteArray calculateDigest(const QByteArray &A2) const; - QByteArray calculateDigest(const QByteArray &A1, const QByteArray &A2) const; - static QByteArray generateNonce(); - - // message parsing and serialization - static QMap parseMessage(const QByteArray &ba); - static QByteArray serializeMessage(const QMap &map); - -private: - QByteArray m_authzid; - QByteArray m_cnonce; - QByteArray m_digestUri; - QByteArray m_nc; - QByteArray m_nonce; - QByteArray m_qop; - QByteArray m_secret; -}; - -#endif diff --git a/src/QXmppSessionIq.cpp b/src/QXmppSessionIq.cpp deleted file mode 100644 index 6672cc0e..00000000 --- a/src/QXmppSessionIq.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include -#include - -#include "QXmppSessionIq.h" -#include "QXmppConstants.h" -#include "QXmppUtils.h" - -bool QXmppSessionIq::isSessionIq(const QDomElement &element) -{ - QDomElement sessionElement = element.firstChildElement("session"); - return (sessionElement.namespaceURI() == ns_session); -} - -void QXmppSessionIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("session");; - writer->writeAttribute("xmlns", ns_session); - writer->writeEndElement(); -} - diff --git a/src/QXmppSessionIq.h b/src/QXmppSessionIq.h deleted file mode 100644 index 2cbcd58c..00000000 --- a/src/QXmppSessionIq.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPSESSIONIQ_H -#define QXMPPSESSIONIQ_H - -#include "QXmppIq.h" - -/// \brief The QXmppSessionIq class represents an IQ used for session -/// establishment as defined by RFC 5921. -/// -/// \ingroup Stanzas - -class QXmppSessionIq : public QXmppIq -{ -public: - /// \cond - static bool isSessionIq(const QDomElement &element); - /// \endcond - -private: - /// \cond - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond -}; - -#endif // QXMPPSESSION_H diff --git a/src/QXmppSocks.cpp b/src/QXmppSocks.cpp deleted file mode 100644 index 1c6f162c..00000000 --- a/src/QXmppSocks.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include -#include -#include -#include -#include - -#include "QXmppSocks.h" - -const static char SocksVersion = 5; - -enum AuthenticationMethod { - NoAuthentication = 0, - GSSAPI = 1, - UsernamePassword = 2, -}; - -enum Command { - ConnectCommand = 1, - BindCommand = 2, - AssociateCommand = 3, -}; - -enum AddressType { - IPv4Address = 1, - DomainName = 3, - IPv6Address = 4, -}; - -enum ReplyType { - Succeeded = 0, - SocksFailure = 1, - ConnectionNotAllowed = 2, - NetworkUnreachable = 3, - HostUnreachable = 4, - ConnectionRefused = 5, - TtlExpired = 6, - CommandNotSupported = 7, - AddressTypeNotSupported = 8, -}; - -enum State { - ConnectState = 0, - CommandState = 1, - ReadyState = 2, -}; - -static QByteArray encodeHostAndPort(quint8 type, const QByteArray &host, quint16 port) -{ - QByteArray buffer; - QDataStream stream(&buffer, QIODevice::WriteOnly); - // set host name - quint8 hostLength = host.size(); - stream << type; - stream << hostLength; - stream.writeRawData(host.constData(), hostLength); - // set port - stream << port; - return buffer; -} - -static bool parseHostAndPort(const QByteArray buffer, quint8 &type, QByteArray &host, quint16 &port) -{ - if (buffer.size() < 4) - return false; - - QDataStream stream(buffer); - // get host name - quint8 hostLength; - stream >> type; - stream >> hostLength; - if (buffer.size() < hostLength + 4) - { - qWarning("Invalid host length"); - return false; - } - host.resize(hostLength); - stream.readRawData(host.data(), hostLength); - // get port - stream >> port; - return true; -} - -QXmppSocksClient::QXmppSocksClient(const QHostAddress &proxyAddress, quint16 proxyPort, QObject *parent) - : QTcpSocket(parent), - m_proxyAddress(proxyAddress), - m_proxyPort(proxyPort), - m_step(ConnectState) -{ - connect(this, SIGNAL(connected()), this, SLOT(slotConnected())); - connect(this, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); -} - -void QXmppSocksClient::connectToHost(const QString &hostName, quint16 hostPort) -{ - m_hostName = hostName; - m_hostPort = hostPort; - QTcpSocket::connectToHost(m_proxyAddress, m_proxyPort); -} - -void QXmppSocksClient::slotConnected() -{ - m_step = ConnectState; - - // disconnect from signal - disconnect(this, SIGNAL(connected()), this, SLOT(slotConnected())); - - // send connect to server - QByteArray buffer; - buffer.resize(3); - buffer[0] = SocksVersion; - buffer[1] = 0x01; // number of methods - buffer[2] = NoAuthentication; - write(buffer); -} - -void QXmppSocksClient::slotReadyRead() -{ - if (m_step == ConnectState) - { - m_step++; - - // receive connect to server response - QByteArray buffer = readAll(); - if (buffer.size() != 2 || buffer.at(0) != SocksVersion || buffer.at(1) != NoAuthentication) - { - qWarning("QXmppSocksClient received an invalid response during handshake"); - close(); - return; - } - - // send CONNECT command - buffer.resize(3); - buffer[0] = SocksVersion; - buffer[1] = ConnectCommand; - buffer[2] = 0x00; // reserved - buffer.append(encodeHostAndPort( - DomainName, - m_hostName.toAscii(), - m_hostPort)); - write(buffer); - - } else if (m_step == CommandState) { - m_step++; - - // disconnect from signal - disconnect(this, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); - - // receive CONNECT response - QByteArray buffer = readAll(); - if (buffer.size() < 6 || - buffer.at(0) != SocksVersion || - buffer.at(1) != Succeeded || - buffer.at(2) != 0) - { - qWarning("QXmppSocksClient received an invalid response to CONNECT command"); - close(); - return; - } - - // parse host - quint8 hostType; - QByteArray hostName; - quint16 hostPort; - if (!parseHostAndPort(buffer.mid(3), hostType, hostName, hostPort)) - { - qWarning("QXmppSocksClient could not parse type/host/port"); - close(); - return; - } - // FIXME : what do we do with the resulting name / port? - - // notify of connection - emit ready(); - } -} - -bool QXmppSocksClient::waitForReady(int msecs) -{ - QEventLoop loop; - connect(this, SIGNAL(disconnected()), &loop, SLOT(quit())); - connect(this, SIGNAL(ready()), &loop, SLOT(quit())); - QTimer::singleShot(msecs, &loop, SLOT(quit())); - loop.exec(); - - if (m_step == ReadyState && isValid()) - return true; - else - return false; -} - -QXmppSocksServer::QXmppSocksServer(QObject *parent) - : QObject(parent) -{ - m_server = new QTcpServer(this); - connect(m_server, SIGNAL(newConnection()), this, SLOT(slotNewConnection())); -} - -void QXmppSocksServer::close() -{ - m_server->close(); -} - -bool QXmppSocksServer::listen(const QHostAddress &address, quint16 port) -{ - return m_server->listen(address, port); -} - -bool QXmppSocksServer::isListening() const -{ - return m_server->isListening(); -} - -QHostAddress QXmppSocksServer::serverAddress() const -{ - return m_server->serverAddress(); -} - -quint16 QXmppSocksServer::serverPort() const -{ - return m_server->serverPort(); -} - -void QXmppSocksServer::slotNewConnection() -{ - QTcpSocket *socket = m_server->nextPendingConnection(); - if (!socket) - return; - - // register socket - m_states.insert(socket, ConnectState); - connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); -} - -void QXmppSocksServer::slotReadyRead() -{ - QTcpSocket *socket = qobject_cast(sender()); - if (!socket || !m_states.contains(socket)) - return; - - if (m_states.value(socket) == ConnectState) - { - m_states.insert(socket, CommandState); - - // receive connect to server request - QByteArray buffer = socket->readAll(); - if (buffer.size() < 3 || - buffer.at(0) != SocksVersion || - buffer.at(1) + 2 != buffer.size()) - { - qWarning("QXmppSocksServer received invalid handshake"); - socket->close(); - return; - } - - // check authentication method - bool foundMethod = false; - for (int i = 2; i < buffer.size(); i++) - { - if (buffer.at(i) == NoAuthentication) - { - foundMethod = true; - break; - } - } - if (!foundMethod) - { - qWarning("QXmppSocksServer received bad authentication method"); - socket->close(); - return; - } - - // send connect to server response - buffer.resize(2); - buffer[0] = SocksVersion; - buffer[1] = NoAuthentication; - socket->write(buffer); - - } else if (m_states.value(socket) == CommandState) { - m_states.insert(socket, ReadyState); - - // disconnect from signals - disconnect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); - - // receive command - QByteArray buffer = socket->readAll(); - if (buffer.size() < 4 || - buffer.at(0) != SocksVersion || - buffer.at(1) != ConnectCommand || - buffer.at(2) != 0x00) - { - qWarning("QXmppSocksServer received an invalid command"); - socket->close(); - return; - } - - // parse host - quint8 hostType; - QByteArray hostName; - quint16 hostPort; - if (!parseHostAndPort(buffer.mid(3), hostType, hostName, hostPort)) - { - qWarning("QXmppSocksServer could not parse type/host/port"); - socket->close(); - return; - } - - // notify of connection - emit newConnection(socket, hostName, hostPort); - - // send response - buffer.resize(3); - buffer[0] = SocksVersion; - buffer[1] = Succeeded; - buffer[2] = 0x00; - buffer.append(encodeHostAndPort( - DomainName, - hostName, - hostPort)); - socket->write(buffer); - } -} - diff --git a/src/QXmppSocks.h b/src/QXmppSocks.h deleted file mode 100644 index 111055fe..00000000 --- a/src/QXmppSocks.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPSOCKS_H -#define QXMPPSOCKS_H - -#include -#include - -class QTcpServer; - -class QXmppSocksClient : public QTcpSocket -{ - Q_OBJECT - -public: - QXmppSocksClient(const QHostAddress &proxyAddress, quint16 proxyPort, QObject *parent=0); - void connectToHost(const QString &hostName, quint16 hostPort); - bool waitForReady(int msecs = 30000); - -signals: - void ready(); - -private slots: - void slotConnected(); - void slotReadyRead(); - -private: - QHostAddress m_proxyAddress; - quint16 m_proxyPort; - QString m_hostName; - quint16 m_hostPort; - int m_step; -}; - -class QXmppSocksServer : public QObject -{ - Q_OBJECT - -public: - QXmppSocksServer(QObject *parent=0); - void close(); - bool isListening() const; - bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0); - - QHostAddress serverAddress() const; - quint16 serverPort() const; - -signals: - void newConnection(QTcpSocket *socket, QString hostName, quint16 port); - -private slots: - void slotNewConnection(); - void slotReadyRead(); - -private: - QTcpServer *m_server; - QMap m_states; -}; - -#endif diff --git a/src/QXmppStanza.cpp b/src/QXmppStanza.cpp deleted file mode 100644 index e8937b6f..00000000 --- a/src/QXmppStanza.cpp +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#include "QXmppStanza.h" -#include "QXmppUtils.h" -#include "QXmppConstants.h" - -#include -#include - -uint QXmppStanza::s_uniqeIdNo = 0; - -QXmppStanza::Error::Error(): - m_code(0), - m_type(static_cast(-1)), - m_condition(static_cast(-1)) -{ -} - -QXmppStanza::Error::Error(Type type, Condition cond, const QString& text): - m_code(0), - m_type(type), - m_condition(cond), - m_text(text) -{ -} - -QXmppStanza::Error::Error(const QString& type, const QString& cond, - const QString& text): - m_code(0), - m_text(text) -{ - setTypeFromStr(type); - setConditionFromStr(cond); -} - -QString QXmppStanza::Error::text() const -{ - return m_text; -} - -void QXmppStanza::Error::setText(const QString& text) -{ - m_text = text; -} - -int QXmppStanza::Error::code() const -{ - return m_code; -} - -void QXmppStanza::Error::setCode(int code) -{ - m_code = code; -} - -QXmppStanza::Error::Condition QXmppStanza::Error::condition() const -{ - return m_condition; -} - -void QXmppStanza::Error::setCondition(QXmppStanza::Error::Condition cond) -{ - m_condition = cond; -} - -QXmppStanza::Error::Type QXmppStanza::Error::type() const -{ - return m_type; -} - -void QXmppStanza::Error::setType(QXmppStanza::Error::Type type) -{ - m_type = type; -} - -QString QXmppStanza::Error::getTypeStr() const -{ - switch(m_type) - { - case Cancel: - return "cancel"; - case Continue: - return "continue"; - case Modify: - return "modify"; - case Auth: - return "auth"; - case Wait: - return "wait"; - default: - return ""; - } -} - -QString QXmppStanza::Error::getConditionStr() const -{ - switch(m_condition) - { - case BadRequest: - return "bad-request"; - case Conflict: - return "conflict"; - case FeatureNotImplemented: - return "feature-not-implemented"; - case Forbidden: - return "forbidden"; - case Gone: - return "gone"; - case InternalServerError: - return "internal-server-error"; - case ItemNotFound: - return "item-not-found"; - case JidMalformed: - return "jid-malformed"; - case NotAcceptable: - return "not-acceptable"; - case NotAllowed: - return "not-allowed"; - case NotAuthorized: - return "not-authorized"; - case PaymentRequired: - return "payment-required"; - case RecipientUnavailable: - return "recipient-unavailable"; - case Redirect: - return "redirect"; - case RegistrationRequired: - return "registration-required"; - case RemoteServerNotFound: - return "remote-server-not-found"; - case RemoteServerTimeout: - return "remote-server-timeout"; - case ResourceConstraint: - return "resource-constraint"; - case ServiceUnavailable: - return "service-unavailable"; - case SubscriptionRequired: - return "subscription-required"; - case UndefinedCondition: - return "undefined-condition"; - case UnexpectedRequest: - return "unexpected-request"; - default: - return ""; - } -} - -void QXmppStanza::Error::setTypeFromStr(const QString& type) -{ - if(type == "cancel") - setType(Cancel); - else if(type == "continue") - setType(Continue); - else if(type == "modify") - setType(Modify); - else if(type == "auth") - setType(Auth); - else if(type == "wait") - setType(Wait); - else - setType(static_cast(-1)); -} - -void QXmppStanza::Error::setConditionFromStr(const QString& type) -{ - if(type == "bad-request") - setCondition(BadRequest); - else if(type == "conflict") - setCondition(Conflict); - else if(type == "feature-not-implemented") - setCondition(FeatureNotImplemented); - else if(type == "forbidden") - setCondition(Forbidden); - else if(type == "gone") - setCondition(Gone); - else if(type == "internal-server-error") - setCondition(InternalServerError); - else if(type == "item-not-found") - setCondition(ItemNotFound); - else if(type == "jid-malformed") - setCondition(JidMalformed); - else if(type == "not-acceptable") - setCondition(NotAcceptable); - else if(type == "not-allowed") - setCondition(NotAllowed); - else if(type == "not-authorized") - setCondition(NotAuthorized); - else if(type == "payment-required") - setCondition(PaymentRequired); - else if(type == "recipient-unavailable") - setCondition(RecipientUnavailable); - else if(type == "redirect") - setCondition(Redirect); - else if(type == "registration-required") - setCondition(RegistrationRequired); - else if(type == "remote-server-not-found") - setCondition(RemoteServerNotFound); - else if(type == "remote-server-timeout") - setCondition(RemoteServerTimeout); - else if(type == "resource-constraint") - setCondition(ResourceConstraint); - else if(type == "service-unavailable") - setCondition(ServiceUnavailable); - else if(type == "subscription-required") - setCondition(SubscriptionRequired); - else if(type == "undefined-condition") - setCondition(UndefinedCondition); - else if(type == "unexpected-request") - setCondition(UnexpectedRequest); - else - setCondition(static_cast(-1)); -} - -bool QXmppStanza::Error::isValid() const -{ - return !(getTypeStr().isEmpty() && getConditionStr().isEmpty()); -} - -void QXmppStanza::Error::parse(const QDomElement &errorElement) -{ - setCode(errorElement.attribute("code").toInt()); - setTypeFromStr(errorElement.attribute("type")); - - QString text; - QString cond; - QDomElement element = errorElement.firstChildElement(); - while(!element.isNull()) - { - if(element.tagName() == "text") - text = element.text(); - else if(element.namespaceURI() == ns_stanza) - { - cond = element.tagName(); - } - element = element.nextSiblingElement(); - } - - setConditionFromStr(cond); - setText(text); -} - -void QXmppStanza::Error::toXml( QXmlStreamWriter *writer ) const -{ - QString cond = getConditionStr(); - QString type = getTypeStr(); - - if(cond.isEmpty() && type.isEmpty()) - return; - - writer->writeStartElement("error"); - helperToXmlAddAttribute(writer, "type", type); - - if (m_code > 0) - helperToXmlAddAttribute(writer, "code", QString::number(m_code)); - - if(!cond.isEmpty()) - { - writer->writeStartElement(cond); - writer->writeAttribute("xmlns", ns_stanza); - writer->writeEndElement(); - } - if(!m_text.isEmpty()) - { - writer->writeStartElement("text"); - writer->writeAttribute("xml:lang", "en"); - writer->writeAttribute("xmlns", ns_stanza); - writer->writeCharacters(m_text); - writer->writeEndElement(); - } - - writer->writeEndElement(); -} - -/// Constructs a QXmppStanza with the specified sender and recipient. -/// -/// \param from -/// \param to - -QXmppStanza::QXmppStanza(const QString& from, const QString& to) - : QXmppPacket(), - m_to(to), - m_from(from) -{ -} - -/// Destroys a QXmppStanza. - -QXmppStanza::~QXmppStanza() -{ -} - -/// Returns the stanza's recipient JID. -/// - -QString QXmppStanza::to() const -{ - return m_to; -} - -/// Sets the stanza's recipient JID. -/// -/// \param to - -void QXmppStanza::setTo(const QString& to) -{ - m_to = to; -} - -/// Returns the stanza's sender JID. - -QString QXmppStanza::from() const -{ - return m_from; -} - -/// Sets the stanza's sender JID. -/// -/// \param from - -void QXmppStanza::setFrom(const QString& from) -{ - m_from = from; -} - -/// Returns the stanza's identifier. - -QString QXmppStanza::id() const -{ - return m_id; -} - -/// Sets the stanza's identifier. -/// -/// \param id - -void QXmppStanza::setId(const QString& id) -{ - m_id = id; -} - -/// Returns the stanza's language. - -QString QXmppStanza::lang() const -{ - return m_lang; -} - -/// Sets the stanza's language. -/// -/// \param lang - -void QXmppStanza::setLang(const QString& lang) -{ - m_lang = lang; -} - -/// Returns the stanza's error. - -QXmppStanza::Error QXmppStanza::error() const -{ - return m_error; -} - -/// Sets the stanza's error. -/// -/// \param error - -void QXmppStanza::setError(const QXmppStanza::Error& error) -{ - m_error = error; -} - -/// Returns the stanza's "extensions". -/// -/// Extensions are XML elements which are not handled internally by QXmpp. - -QXmppElementList QXmppStanza::extensions() const -{ - return m_extensions; -} - -/// Sets the stanza's "extensions". -/// -/// \param extensions - -void QXmppStanza::setExtensions(const QXmppElementList &extensions) -{ - m_extensions = extensions; -} - -void QXmppStanza::generateAndSetNextId() -{ - // get back - ++s_uniqeIdNo; - m_id = "qxmpp" + QString::number(s_uniqeIdNo); -} - -bool QXmppStanza::isErrorStanza() const -{ - return m_error.isValid(); -} - -void QXmppStanza::parse(const QDomElement &element) -{ - m_from = element.attribute("from"); - m_to = element.attribute("to"); - m_id = element.attribute("id"); - m_lang = element.attribute("lang"); - - QDomElement errorElement = element.firstChildElement("error"); - if(!errorElement.isNull()) - m_error.parse(errorElement); -} - diff --git a/src/QXmppStanza.h b/src/QXmppStanza.h deleted file mode 100644 index dc1c1346..00000000 --- a/src/QXmppStanza.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPSTANZA_H -#define QXMPPSTANZA_H - -#include "QXmppElement.h" -#include "QXmppPacket.h" -#include - -// forward declarations of QXmlStream* classes will not work on Mac, we need to -// include the whole header. -// See http://lists.trolltech.com/qt-interest/2008-07/thread00798-0.html -// for an explanation. -#include - -/// \defgroup Stanzas - -/// \brief The QXmppStanza class is the base class for all XMPP stanzas. -/// -/// \ingroup Stanzas - -class QXmppStanza : public QXmppPacket -{ -public: - class Error - { - public: - enum Type - { - Cancel, - Continue, - Modify, - Auth, - Wait - }; - - enum Condition - { - BadRequest, - Conflict, - FeatureNotImplemented, - Forbidden, - Gone, - InternalServerError, - ItemNotFound, - JidMalformed, - NotAcceptable, - NotAllowed, - NotAuthorized, - PaymentRequired, - RecipientUnavailable, - Redirect, - RegistrationRequired, - RemoteServerNotFound, - RemoteServerTimeout, - ResourceConstraint, - ServiceUnavailable, - SubscriptionRequired, - UndefinedCondition, - UnexpectedRequest - }; - - Error(); - Error(Type type, Condition cond, const QString& text=""); - Error(const QString& type, const QString& cond, const QString& text=""); - - int code() const; - void setCode(int code); - - QString text() const; - void setText(const QString& text); - - Condition condition() const; - void setCondition(Condition cond); - - void setType(Type type); - Type type() const; - - // FIXME : remove this once is gone - bool isValid() const; - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - - private: - QString getConditionStr() const; - void setConditionFromStr(const QString& cond); - - QString getTypeStr() const; - void setTypeFromStr(const QString& type); - - int m_code; - Type m_type; - Condition m_condition; - QString m_text; - }; - - QXmppStanza(const QString& from = QString(), const QString& to = QString()); - ~QXmppStanza(); - - QString to() const; - void setTo(const QString&); - - QString from() const; - void setFrom(const QString&); - - QString id() const; - void setId(const QString&); - - QString lang() const; - void setLang(const QString&); - - QXmppStanza::Error error() const; - void setError(const QXmppStanza::Error& error); - - QXmppElementList extensions() const; - void setExtensions(const QXmppElementList &elements); - - /// \cond - // FIXME : why is this needed? - bool isErrorStanza() const; - -protected: - void generateAndSetNextId(); - void parse(const QDomElement &element); - /// \endcond - -private: - static uint s_uniqeIdNo; - QString m_to; - QString m_from; - QString m_id; - QString m_lang; - QXmppStanza::Error m_error; - QXmppElementList m_extensions; -}; - -#endif // QXMPPSTANZA_H diff --git a/src/QXmppStream.cpp b/src/QXmppStream.cpp deleted file mode 100644 index d9f7ff88..00000000 --- a/src/QXmppStream.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#include "QXmppConstants.h" -#include "QXmppLogger.h" -#include "QXmppPacket.h" -#include "QXmppStream.h" -#include "QXmppUtils.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -static bool randomSeeded = false; -static const QByteArray streamRootElementEnd = ""; - -class QXmppStreamPrivate -{ -public: - QXmppStreamPrivate(); - - QByteArray dataBuffer; - QSslSocket* socket; - - // stream state - QByteArray streamStart; -}; - -QXmppStreamPrivate::QXmppStreamPrivate() - : socket(0) -{ -} - -/// Constructs a base XMPP stream. -/// -/// \param parent - -QXmppStream::QXmppStream(QObject *parent) - : QXmppLoggable(parent), - d(new QXmppStreamPrivate) -{ - // Make sure the random number generator is seeded - if (!randomSeeded) - { - qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); - randomSeeded = true; - } -} - -/// Destroys a base XMPP stream. - -QXmppStream::~QXmppStream() -{ - delete d; -} - -/// Disconnects from the remote host. -/// - -void QXmppStream::disconnectFromHost() -{ - sendData(streamRootElementEnd); - if (d->socket) - { - d->socket->flush(); - d->socket->disconnectFromHost(); - } -} - -/// Handles a stream start event, which occurs when the underlying transport -/// becomes ready (socket connected, encryption started). -/// -/// If you redefine handleStart(), make sure to call the base class's method. - -void QXmppStream::handleStart() -{ - d->dataBuffer.clear(); - d->streamStart.clear(); -} - -/// Returns true if the stream is connected. -/// - -bool QXmppStream::isConnected() const -{ - return d->socket && - d->socket->state() == QAbstractSocket::ConnectedState; -} - -/// Sends raw data to the peer. -/// -/// \param data - -bool QXmppStream::sendData(const QByteArray &data) -{ - logSent(QString::fromUtf8(data)); - if (!d->socket || d->socket->state() != QAbstractSocket::ConnectedState) - return false; - return d->socket->write(data) == data.size(); -} - -/// Sends an XMPP packet to the peer. -/// -/// \param packet - -bool QXmppStream::sendPacket(const QXmppPacket &packet) -{ - // prepare packet - QByteArray data; - QXmlStreamWriter xmlStream(&data); - packet.toXml(&xmlStream); - - // send packet - return sendData(data); -} - -/// Returns the QSslSocket used for this stream. -/// - -QSslSocket *QXmppStream::socket() const -{ - return d->socket; -} - -/// Sets the QSslSocket used for this stream. -/// - -void QXmppStream::setSocket(QSslSocket *socket) -{ - bool check; - Q_UNUSED(check); - - d->socket = socket; - if (!d->socket) - return; - - // socket events - check = connect(socket, SIGNAL(connected()), - this, SLOT(_q_socketConnected())); - Q_ASSERT(check); - - check = connect(socket, SIGNAL(disconnected()), - this, SLOT(_q_socketDisconnected())); - Q_ASSERT(check); - - check = connect(socket, SIGNAL(encrypted()), - this, SLOT(_q_socketEncrypted())); - Q_ASSERT(check); - - check = connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), - this, SLOT(_q_socketError(QAbstractSocket::SocketError))); - - check = connect(socket, SIGNAL(readyRead()), - this, SLOT(_q_socketReadyRead())); - Q_ASSERT(check); - - // relay signals - check = connect(socket, SIGNAL(disconnected()), - this, SIGNAL(disconnected())); - Q_ASSERT(check); -} - -void QXmppStream::_q_socketConnected() -{ - info(QString("Socket connected to %1 %2").arg( - d->socket->peerAddress().toString(), - QString::number(d->socket->peerPort()))); - handleStart(); -} - -void QXmppStream::_q_socketDisconnected() -{ - info("Socket disconnected"); -} - -void QXmppStream::_q_socketEncrypted() -{ - debug("Socket encrypted"); - handleStart(); -} - -void QXmppStream::_q_socketError(QAbstractSocket::SocketError socketError) -{ - Q_UNUSED(socketError); - warning(QString("Socket error: " + socket()->errorString())); -} - -void QXmppStream::_q_socketReadyRead() -{ - d->dataBuffer.append(d->socket->readAll()); - - // FIXME : maybe these QRegExps could be static? - QRegExp startStreamRegex("^(<\\?xml.*\\?>)?\\s*"); - startStreamRegex.setMinimal(true); - QRegExp endStreamRegex("$"); - endStreamRegex.setMinimal(true); - - // check whether we need to add stream start / end elements - QByteArray completeXml = d->dataBuffer; - const QString strData = QString::fromUtf8(d->dataBuffer); - bool streamStart = false; - if (d->streamStart.isEmpty() && strData.contains(startStreamRegex)) - streamStart = true; - else - completeXml.prepend(d->streamStart); - if (!strData.contains(endStreamRegex)) - completeXml.append(streamRootElementEnd); - - // check whether we have a valid XML document - QDomDocument doc; - if (!doc.setContent(completeXml, true)) - return; - - // remove data from buffer - logReceived(strData); - d->dataBuffer.clear(); - if (streamStart) - d->streamStart = startStreamRegex.cap(0).toUtf8(); - - // process stream start - if (streamStart) - handleStream(doc.documentElement()); - - // process stanzas - QDomElement nodeRecv = doc.documentElement().firstChildElement(); - while (!nodeRecv.isNull()) { - handleStanza(nodeRecv); - nodeRecv = nodeRecv.nextSiblingElement(); - } -} - - diff --git a/src/QXmppStream.h b/src/QXmppStream.h deleted file mode 100644 index bcbb7616..00000000 --- a/src/QXmppStream.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPSTREAM_H -#define QXMPPSTREAM_H - -#include -#include -#include "QXmppLogger.h" - -class QDomElement; -class QSslSocket; -class QXmppPacket; -class QXmppStreamPrivate; - -/// \brief The QXmppStream class is the base class for all XMPP streams. -/// - -class QXmppStream : public QXmppLoggable -{ - Q_OBJECT - -public: - QXmppStream(QObject *parent); - ~QXmppStream(); - - virtual bool isConnected() const; - bool sendPacket(const QXmppPacket&); - -signals: - /// This signal is emitted when the stream is connected. - void connected(); - - /// This signal is emitted when the stream is disconnected. - void disconnected(); - -protected: - // Access to underlying socket - QSslSocket *socket() const; - void setSocket(QSslSocket *socket); - - // Overridable methods - virtual void handleStart(); - - /// Handles an incoming XMPP stanza. - /// - /// \param element - virtual void handleStanza(const QDomElement &element) = 0; - - /// Handles an incoming XMPP stream start. - /// - /// \param element - virtual void handleStream(const QDomElement &element) = 0; - -public slots: - virtual void disconnectFromHost(); - virtual bool sendData(const QByteArray&); - -private slots: - void _q_socketConnected(); - void _q_socketDisconnected(); - void _q_socketEncrypted(); - void _q_socketError(QAbstractSocket::SocketError error); - void _q_socketReadyRead(); - -private: - QXmppStreamPrivate * const d; -}; - -#endif // QXMPPSTREAM_H diff --git a/src/QXmppStreamFeatures.cpp b/src/QXmppStreamFeatures.cpp deleted file mode 100644 index 241f676f..00000000 --- a/src/QXmppStreamFeatures.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include "QXmppConstants.h" -#include "QXmppStreamFeatures.h" - -QXmppStreamFeatures::QXmppStreamFeatures() - : m_bindMode(Disabled), - m_sessionMode(Disabled), - m_nonSaslAuthMode(Disabled), - m_tlsMode(Disabled) -{ -} - -QXmppStreamFeatures::Mode QXmppStreamFeatures::bindMode() const -{ - return m_bindMode; -} - -void QXmppStreamFeatures::setBindMode(QXmppStreamFeatures::Mode mode) -{ - m_bindMode = mode; -} - -QXmppStreamFeatures::Mode QXmppStreamFeatures::sessionMode() const -{ - return m_sessionMode; -} - -void QXmppStreamFeatures::setSessionMode(Mode mode) -{ - m_sessionMode = mode; -} - -QXmppStreamFeatures::Mode QXmppStreamFeatures::nonSaslAuthMode() const -{ - return m_nonSaslAuthMode; -} - -void QXmppStreamFeatures::setNonSaslAuthMode(QXmppStreamFeatures::Mode mode) -{ - m_nonSaslAuthMode = mode; -} - -QList QXmppStreamFeatures::authMechanisms() const -{ - return m_authMechanisms; -} - -void QXmppStreamFeatures::setAuthMechanisms(QList &mechanisms) -{ - m_authMechanisms = mechanisms; -} - -QList QXmppStreamFeatures::compressionMethods() const -{ - return m_compressionMethods; -} - -void QXmppStreamFeatures::setCompressionMethods(QList &methods) -{ - m_compressionMethods = methods; -} - -QXmppStreamFeatures::Mode QXmppStreamFeatures::tlsMode() const -{ - return m_tlsMode; -} - -void QXmppStreamFeatures::setTlsMode(QXmppStreamFeatures::Mode mode) -{ - m_tlsMode = mode; -} - -bool QXmppStreamFeatures::isStreamFeatures(const QDomElement &element) -{ - return element.namespaceURI() == ns_stream && - element.tagName() == "features"; -} - -static QXmppStreamFeatures::Mode readFeature(const QDomElement &element, const char *tagName, const char *tagNs) -{ - QDomElement subElement = element.firstChildElement(tagName); - if (subElement.namespaceURI() == tagNs) - { - if (!subElement.firstChildElement("required").isNull()) - return QXmppStreamFeatures::Required; - else - return QXmppStreamFeatures::Enabled; - } else { - return QXmppStreamFeatures::Disabled; - } -} - -void QXmppStreamFeatures::parse(const QDomElement &element) -{ - m_bindMode = readFeature(element, "bind", ns_bind); - m_sessionMode = readFeature(element, "session", ns_session); - m_nonSaslAuthMode = readFeature(element, "auth", ns_authFeature); - m_tlsMode = readFeature(element, "starttls", ns_tls); - - // parse advertised compression methods - QDomElement compression = element.firstChildElement("compression"); - if (compression.namespaceURI() == ns_compressFeature) - { - QDomElement subElement = compression.firstChildElement("method"); - while(!subElement.isNull()) - { - if (subElement.text() == QLatin1String("zlib")) - m_compressionMethods << QXmppConfiguration::ZlibCompression; - subElement = subElement.nextSiblingElement("method"); - } - } - - // parse advertised SASL Authentication mechanisms - QDomElement mechs = element.firstChildElement("mechanisms"); - if (mechs.namespaceURI() == ns_sasl) - { - QDomElement subElement = mechs.firstChildElement("mechanism"); - while(!subElement.isNull()) - { - if (subElement.text() == QLatin1String("PLAIN")) - m_authMechanisms << QXmppConfiguration::SASLPlain; - else if (subElement.text() == QLatin1String("DIGEST-MD5")) - m_authMechanisms << QXmppConfiguration::SASLDigestMD5; - else if (subElement.text() == QLatin1String("ANONYMOUS")) - m_authMechanisms << QXmppConfiguration::SASLAnonymous; - else if (subElement.text() == QLatin1String("X-FACEBOOK-PLATFORM")) - m_authMechanisms << QXmppConfiguration::SASLXFacebookPlatform; - subElement = subElement.nextSiblingElement("mechanism"); - } - } -} - -static void writeFeature(QXmlStreamWriter *writer, const char *tagName, const char *tagNs, QXmppStreamFeatures::Mode mode) -{ - if (mode != QXmppStreamFeatures::Disabled) - { - writer->writeStartElement(tagName); - writer->writeAttribute("xmlns", tagNs); - if (mode == QXmppStreamFeatures::Required) - writer->writeEmptyElement("required"); - writer->writeEndElement(); - } -} - -void QXmppStreamFeatures::toXml(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("stream:features"); - writeFeature(writer, "bind", ns_bind, m_bindMode); - writeFeature(writer, "session", ns_session, m_sessionMode); - writeFeature(writer, "auth", ns_authFeature, m_nonSaslAuthMode); - writeFeature(writer, "starttls", ns_tls, m_tlsMode); - - if (!m_compressionMethods.isEmpty()) - { - writer->writeStartElement("compression"); - writer->writeAttribute("xmlns", ns_compressFeature); - for (int i = 0; i < m_compressionMethods.size(); i++) - { - writer->writeStartElement("method"); - switch (m_compressionMethods[i]) - { - case QXmppConfiguration::ZlibCompression: - writer->writeCharacters("zlib"); - break; - } - writer->writeEndElement(); - } - writer->writeEndElement(); - } - if (!m_authMechanisms.isEmpty()) - { - writer->writeStartElement("mechanisms"); - writer->writeAttribute("xmlns", ns_sasl); - for (int i = 0; i < m_authMechanisms.size(); i++) - { - writer->writeStartElement("mechanism"); - switch (m_authMechanisms[i]) - { - case QXmppConfiguration::SASLPlain: - writer->writeCharacters("PLAIN"); - break; - case QXmppConfiguration::SASLDigestMD5: - writer->writeCharacters("DIGEST-MD5"); - break; - case QXmppConfiguration::SASLAnonymous: - writer->writeCharacters("ANONYMOUS"); - break; - case QXmppConfiguration::SASLXFacebookPlatform: - writer->writeCharacters("X-FACEBOOK-PLATFORM"); - break; - } - writer->writeEndElement(); - } - writer->writeEndElement(); - } - writer->writeEndElement(); -} - diff --git a/src/QXmppStreamFeatures.h b/src/QXmppStreamFeatures.h deleted file mode 100644 index bfc42c64..00000000 --- a/src/QXmppStreamFeatures.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPSTREAMFEATURES_H -#define QXMPPSTREAMFEATURES_H - -#include "QXmppConfiguration.h" -#include "QXmppStanza.h" - -class QXmppStreamFeatures : public QXmppStanza -{ -public: - QXmppStreamFeatures(); - - enum Mode - { - Disabled = 0, - Enabled, - Required - }; - - Mode bindMode() const; - void setBindMode(Mode mode); - - Mode sessionMode() const; - void setSessionMode(Mode mode); - - Mode nonSaslAuthMode() const; - void setNonSaslAuthMode(Mode mode); - - QList authMechanisms() const; - void setAuthMechanisms(QList &mecanisms); - - QList compressionMethods() const; - void setCompressionMethods(QList &methods); - - Mode tlsMode() const; - void setTlsMode(Mode mode); - - /// \cond - void parse(const QDomElement &element); - void toXml(QXmlStreamWriter *writer) const; - /// \endcond - - static bool isStreamFeatures(const QDomElement &element); - -private: - Mode m_bindMode; - Mode m_sessionMode; - Mode m_nonSaslAuthMode; - Mode m_tlsMode; - QList m_authMechanisms; - QList m_compressionMethods; -}; - -#endif diff --git a/src/QXmppStreamInitiationIq.cpp b/src/QXmppStreamInitiationIq.cpp deleted file mode 100644 index 32dd0c78..00000000 --- a/src/QXmppStreamInitiationIq.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include "QXmppConstants.h" -#include "QXmppStreamInitiationIq.h" -#include "QXmppUtils.h" - -QString QXmppStreamInitiationIq::mimeType() const -{ - return m_mimeType; -} - -void QXmppStreamInitiationIq::setMimeType(const QString &mimeType) -{ - m_mimeType = mimeType; -} - -QXmppStreamInitiationIq::Profile QXmppStreamInitiationIq::profile() const -{ - return m_profile; -} - -void QXmppStreamInitiationIq::setProfile(QXmppStreamInitiationIq::Profile profile) -{ - m_profile = profile; -} - -QXmppElementList QXmppStreamInitiationIq::siItems() const -{ - return m_siItems; -} - -QString QXmppStreamInitiationIq::siId() const -{ - return m_siId; -} - -void QXmppStreamInitiationIq::setSiId(const QString &id) -{ - m_siId = id; -} - -void QXmppStreamInitiationIq::setSiItems(const QXmppElementList &items) -{ - m_siItems = items; -} - -bool QXmppStreamInitiationIq::isStreamInitiationIq(const QDomElement &element) -{ - QDomElement siElement = element.firstChildElement("si"); - return (siElement.namespaceURI() == ns_stream_initiation); -} - -void QXmppStreamInitiationIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement siElement = element.firstChildElement("si"); - m_siId = siElement.attribute("id"); - m_mimeType = siElement.attribute("mime-type"); - if (siElement.attribute("profile") == ns_stream_initiation_file_transfer) - m_profile = FileTransfer; - else - m_profile = None; - - QDomElement itemElement = siElement.firstChildElement(); - while (!itemElement.isNull()) - { - m_siItems.append(QXmppElement(itemElement)); - itemElement = itemElement.nextSiblingElement(); - } -} - -void QXmppStreamInitiationIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("si"); - writer->writeAttribute("xmlns", ns_stream_initiation); - helperToXmlAddAttribute(writer, "id", m_siId); - helperToXmlAddAttribute(writer, "mime-type", m_mimeType); - if (m_profile == FileTransfer) - helperToXmlAddAttribute(writer, "profile", ns_stream_initiation_file_transfer); - foreach (const QXmppElement &item, m_siItems) - item.toXml(writer); - writer->writeEndElement(); -} - diff --git a/src/QXmppStreamInitiationIq.h b/src/QXmppStreamInitiationIq.h deleted file mode 100644 index 27739b46..00000000 --- a/src/QXmppStreamInitiationIq.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPSTREAMINITIATIONIQ_H -#define QXMPPSTREAMINITIATIONIQ_H - -#include - -#include "QXmppIq.h" - -class QDomElement; -class QXmlStreamWriter; - -class QXmppStreamInitiationIq : public QXmppIq -{ -public: - enum Profile { - None = 0, - FileTransfer, - }; - - QString mimeType() const; - void setMimeType(const QString &mimeType); - - QXmppStreamInitiationIq::Profile profile() const; - void setProfile(QXmppStreamInitiationIq::Profile profile); - - QString siId() const; - void setSiId(const QString &id); - - QXmppElementList siItems() const; - void setSiItems(const QXmppElementList &items); - - static bool isStreamInitiationIq(const QDomElement &element); - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString m_mimeType; - Profile m_profile; - QString m_siId; - QXmppElementList m_siItems; -}; - -#endif diff --git a/src/QXmppStun.cpp b/src/QXmppStun.cpp deleted file mode 100644 index 16cef928..00000000 --- a/src/QXmppStun.cpp +++ /dev/null @@ -1,2581 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#define QXMPP_DEBUG_STUN - -#include -#include -#include -#include -#include - -#include "QXmppStun.h" -#include "QXmppUtils.h" - -#define ID_SIZE 12 -#define STUN_RTO_INTERVAL 500 -#define STUN_RTO_MAX 7 - -static const quint32 STUN_MAGIC = 0x2112A442; -static const quint16 STUN_HEADER = 20; -static const quint8 STUN_IPV4 = 0x01; -static const quint8 STUN_IPV6 = 0x02; - -enum AttributeType { - MappedAddress = 0x0001, // RFC5389 - ChangeRequest = 0x0003, // RFC5389 - SourceAddress = 0x0004, // RFC5389 - ChangedAddress = 0x0005, // RFC5389 - Username = 0x0006, // RFC5389 - MessageIntegrity = 0x0008, // RFC5389 - ErrorCode = 0x0009, // RFC5389 - ChannelNumber = 0x000c, // RFC5766 : TURN - Lifetime = 0x000d, // RFC5766 : TURN - XorPeerAddress = 0x0012, // RFC5766 : TURN - DataAttr = 0x0013, // RFC5766 : TURN - Realm = 0x0014, // RFC5389 - Nonce = 0x0015, // RFC5389 - XorRelayedAddress= 0x0016, // RFC5766 : TURN - EvenPort = 0x0018, // RFC5766 : TURN - RequestedTransport=0x0019, // RFC5766 : TURN - XorMappedAddress = 0x0020, // RFC5389 - ReservationToken = 0x0022, // RFC5766 : TURN - Priority = 0x0024, // RFC5245 - UseCandidate = 0x0025, // RFC5245 - Software = 0x8022, // RFC5389 - Fingerprint = 0x8028, // RFC5389 - IceControlled = 0x8029, // RFC5245 - IceControlling = 0x802a, // RFC5245 - OtherAddress = 0x802c, // RFC5780 -}; - -// FIXME : we need to set local preference to discriminate between -// multiple IP addresses -static quint32 candidatePriority(const QXmppJingleCandidate &candidate, int localPref = 65535) -{ - int typePref; - switch (candidate.type()) - { - case QXmppJingleCandidate::HostType: - typePref = 126; - break; - case QXmppJingleCandidate::PeerReflexiveType: - typePref = 110; - break; - case QXmppJingleCandidate::ServerReflexiveType: - typePref = 100; - break; - default: - typePref = 0; - } - - return (1 << 24) * typePref + \ - (1 << 8) * localPref + \ - (256 - candidate.component()); -} - -static bool isIPv6LinkLocalAddress(const QHostAddress &addr) -{ - if (addr.protocol() != QAbstractSocket::IPv6Protocol) - return false; - Q_IPV6ADDR ipv6addr = addr.toIPv6Address(); - return (((ipv6addr[0] << 8) + ipv6addr[1]) & 0xffc0) == 0xfe80; -} - -static bool decodeAddress(QDataStream &stream, quint16 a_length, QHostAddress &address, quint16 &port, const QByteArray &xorId = QByteArray()) -{ - if (a_length < 4) - return false; - quint8 reserved, protocol; - quint16 rawPort; - stream >> reserved; - stream >> protocol; - stream >> rawPort; - if (xorId.isEmpty()) - port = rawPort; - else - port = rawPort ^ (STUN_MAGIC >> 16); - if (protocol == STUN_IPV4) - { - if (a_length != 8) - return false; - quint32 addr; - stream >> addr; - if (xorId.isEmpty()) - address = QHostAddress(addr); - else - address = QHostAddress(addr ^ STUN_MAGIC); - } else if (protocol == STUN_IPV6) { - if (a_length != 20) - return false; - Q_IPV6ADDR addr; - stream.readRawData((char*)&addr, sizeof(addr)); - if (!xorId.isEmpty()) - { - QByteArray xpad; - QDataStream(&xpad, QIODevice::WriteOnly) << STUN_MAGIC; - xpad += xorId; - for (int i = 0; i < 16; i++) - addr[i] ^= xpad[i]; - } - address = QHostAddress(addr); - } else { - return false; - } - return true; -} - -static void encodeAddress(QDataStream &stream, quint16 type, const QHostAddress &address, quint16 port, const QByteArray &xorId = QByteArray()) -{ - const quint8 reserved = 0; - if (address.protocol() == QAbstractSocket::IPv4Protocol) - { - stream << type; - stream << quint16(8); - stream << reserved; - stream << quint8(STUN_IPV4); - quint32 addr = address.toIPv4Address(); - if (!xorId.isEmpty()) - { - port ^= (STUN_MAGIC >> 16); - addr ^= STUN_MAGIC; - } - stream << port; - stream << addr; - } else if (address.protocol() == QAbstractSocket::IPv6Protocol) { - stream << type; - stream << quint16(20); - stream << reserved; - stream << quint8(STUN_IPV6); - Q_IPV6ADDR addr = address.toIPv6Address(); - if (!xorId.isEmpty()) - { - port ^= (STUN_MAGIC >> 16); - QByteArray xpad; - QDataStream(&xpad, QIODevice::WriteOnly) << STUN_MAGIC; - xpad += xorId; - for (int i = 0; i < 16; i++) - addr[i] ^= xpad[i]; - } - stream << port; - stream.writeRawData((char*)&addr, sizeof(addr)); - } else { - qWarning("Cannot write STUN attribute for unknown IP version"); - } -} - -static void addAddress(QDataStream &stream, quint16 type, const QHostAddress &host, quint16 port, const QByteArray &xorId = QByteArray()) -{ - if (port && !host.isNull() && - (host.protocol() == QAbstractSocket::IPv4Protocol || - host.protocol() == QAbstractSocket::IPv6Protocol)) - { - encodeAddress(stream, type, host, port, xorId); - } -} - -static void encodeString(QDataStream &stream, quint16 type, const QString &string) -{ - const QByteArray utf8string = string.toUtf8(); - stream << type; - stream << quint16(utf8string.size()); - stream.writeRawData(utf8string.data(), utf8string.size()); - if (utf8string.size() % 4) - { - const QByteArray padding(4 - (utf8string.size() % 4), 0); - stream.writeRawData(padding.data(), padding.size()); - } -} - -static void setBodyLength(QByteArray &buffer, qint16 length) -{ - QDataStream stream(&buffer, QIODevice::WriteOnly); - stream.device()->seek(2); - stream << length; -} - -/// Constructs a new QXmppStunMessage. - -QXmppStunMessage::QXmppStunMessage() - : errorCode(0), - changedPort(0), - mappedPort(0), - otherPort(0), - sourcePort(0), - xorMappedPort(0), - xorPeerPort(0), - xorRelayedPort(0), - useCandidate(false), - m_cookie(STUN_MAGIC), - m_type(0), - m_changeRequest(0), - m_channelNumber(0), - m_lifetime(0), - m_priority(0) -{ - m_id = QByteArray(ID_SIZE, 0); -} - -quint32 QXmppStunMessage::cookie() const -{ - return m_cookie; -} - -void QXmppStunMessage::setCookie(quint32 cookie) -{ - m_cookie = cookie; -} - -QByteArray QXmppStunMessage::id() const -{ - return m_id; -} - -void QXmppStunMessage::setId(const QByteArray &id) -{ - Q_ASSERT(id.size() == ID_SIZE); - m_id = id; -} - -quint16 QXmppStunMessage::messageClass() const -{ - return m_type & 0x0110; -} - -quint16 QXmppStunMessage::messageMethod() const -{ - return m_type & 0x3eef; -} - -quint16 QXmppStunMessage::type() const -{ - return m_type; -} - -void QXmppStunMessage::setType(quint16 type) -{ - m_type = type; -} - -/// Returns the CHANGE-REQUEST attribute, indicating whether to change -/// the IP and / or port from which the response is sent. - -quint32 QXmppStunMessage::changeRequest() const -{ - return m_changeRequest; -} - -/// Sets the CHANGE-REQUEST attribute, indicating whether to change -/// the IP and / or port from which the response is sent. -/// -/// \param changeRequest - -void QXmppStunMessage::setChangeRequest(quint32 changeRequest) -{ - m_changeRequest = changeRequest; - m_attributes << ChangeRequest; -} - -/// Returns the CHANNEL-NUMBER attribute. - -quint16 QXmppStunMessage::channelNumber() const -{ - return m_channelNumber; -} - -/// Sets the CHANNEL-NUMBER attribute. -/// -/// \param channelNumber - -void QXmppStunMessage::setChannelNumber(quint16 channelNumber) -{ - m_channelNumber = channelNumber; - m_attributes << ChannelNumber; -} - -/// Returns the DATA attribute. - -QByteArray QXmppStunMessage::data() const -{ - return m_data; -} - -/// Sets the DATA attribute. - -void QXmppStunMessage::setData(const QByteArray &data) -{ - m_data = data; - m_attributes << DataAttr; -} - -/// Returns the LIFETIME attribute, indicating the duration in seconds for -/// which the server will maintain an allocation. - -quint32 QXmppStunMessage::lifetime() const -{ - return m_lifetime; -} - -/// Sets the LIFETIME attribute, indicating the duration in seconds for -/// which the server will maintain an allocation. -/// -/// \param lifetime - -void QXmppStunMessage::setLifetime(quint32 lifetime) -{ - m_lifetime = lifetime; - m_attributes << Lifetime; -} - -/// Returns the NONCE attribute. - -QByteArray QXmppStunMessage::nonce() const -{ - return m_nonce; -} - -/// Sets the NONCE attribute. -/// -/// \param nonce - -void QXmppStunMessage::setNonce(const QByteArray &nonce) -{ - m_nonce = nonce; - m_attributes << Nonce; -} - -/// Returns the PRIORITY attribute, the priority that would be assigned to -/// a peer reflexive candidate discovered during the ICE check. - -quint32 QXmppStunMessage::priority() const -{ - return m_priority; -} - -/// Sets the PRIORITY attribute, the priority that would be assigned to -/// a peer reflexive candidate discovered during the ICE check. -/// -/// \param priority - -void QXmppStunMessage::setPriority(quint32 priority) -{ - m_priority = priority; - m_attributes << Priority; -} - -/// Returns the REALM attribute. - -QString QXmppStunMessage::realm() const -{ - return m_realm; -} - -/// Sets the REALM attribute. -/// -/// \param realm - -void QXmppStunMessage::setRealm(const QString &realm) -{ - m_realm = realm; - m_attributes << Realm; -} - -/// Returns the REQUESTED-TRANSPORT attribute. - -quint8 QXmppStunMessage::requestedTransport() const -{ - return m_requestedTransport; -} - -/// Sets the REQUESTED-TRANSPORT attribute. -/// -/// \param requestedTransport - -void QXmppStunMessage::setRequestedTransport(quint8 requestedTransport) -{ - m_requestedTransport = requestedTransport; - m_attributes << RequestedTransport; -} - -/// Returns the RESERVATION-TOKEN attribute. - -QByteArray QXmppStunMessage::reservationToken() const -{ - return m_reservationToken; -} - -/// Sets the RESERVATION-TOKEN attribute. -/// -/// \param reservationToken - -void QXmppStunMessage::setReservationToken(const QByteArray &reservationToken) -{ - m_reservationToken = reservationToken; - m_reservationToken.resize(8); - m_attributes << ReservationToken; -} - -/// Returns the SOFTWARE attribute, containing a textual description of the -/// software being used. - -QString QXmppStunMessage::software() const -{ - return m_software; -} - -/// Sets the SOFTWARE attribute, containing a textual description of the -/// software being used. -/// -/// \param software - -void QXmppStunMessage::setSoftware(const QString &software) -{ - m_software = software; - m_attributes << Software; -} - -/// Returns the USERNAME attribute, containing the username to use for -/// authentication. - -QString QXmppStunMessage::username() const -{ - return m_username; -} - -/// Sets the USERNAME attribute, containing the username to use for -/// authentication. -/// -/// \param username - -void QXmppStunMessage::setUsername(const QString &username) -{ - m_username = username; - m_attributes << Username; -} - -/// Decodes a QXmppStunMessage and checks its integrity using the given key. -/// -/// \param buffer -/// \param key -/// \param errors - -bool QXmppStunMessage::decode(const QByteArray &buffer, const QByteArray &key, QStringList *errors) -{ - QStringList silent; - if (!errors) - errors = &silent; - - if (buffer.size() < STUN_HEADER) - { - *errors << QLatin1String("Received a truncated STUN packet"); - return false; - } - - // parse STUN header - QDataStream stream(buffer); - quint16 length; - stream >> m_type; - stream >> length; - stream >> m_cookie; - stream.readRawData(m_id.data(), m_id.size()); - - if (length != buffer.size() - STUN_HEADER) - { - *errors << QLatin1String("Received an invalid STUN packet"); - return false; - } - - // parse STUN attributes - int done = 0; - bool after_integrity = false; - while (done < length) - { - quint16 a_type, a_length; - stream >> a_type; - stream >> a_length; - const int pad_length = 4 * ((a_length + 3) / 4) - a_length; - - // only FINGERPRINT is allowed after MESSAGE-INTEGRITY - if (after_integrity && a_type != Fingerprint) - { - *errors << QString("Skipping attribute %1 after MESSAGE-INTEGRITY").arg(QString::number(a_type)); - stream.skipRawData(a_length + pad_length); - done += 4 + a_length + pad_length; - continue; - } - - if (a_type == Priority) - { - // PRIORITY - if (a_length != sizeof(m_priority)) - return false; - stream >> m_priority; - m_attributes << Priority; - - } else if (a_type == ErrorCode) { - - // ERROR-CODE - if (a_length < 4) - return false; - quint16 reserved; - quint8 errorCodeHigh, errorCodeLow; - stream >> reserved; - stream >> errorCodeHigh; - stream >> errorCodeLow; - errorCode = errorCodeHigh * 100 + errorCodeLow; - QByteArray phrase(a_length - 4, 0); - stream.readRawData(phrase.data(), phrase.size()); - errorPhrase = QString::fromUtf8(phrase); - - } else if (a_type == UseCandidate) { - - // USE-CANDIDATE - if (a_length != 0) - return false; - useCandidate = true; - - } else if (a_type == ChannelNumber) { - - // CHANNEL-NUMBER - if (a_length != 4) - return false; - stream >> m_channelNumber; - stream.skipRawData(2); - m_attributes << ChannelNumber; - - } else if (a_type == DataAttr) { - - // DATA - m_data.resize(a_length); - stream.readRawData(m_data.data(), m_data.size()); - m_attributes << DataAttr; - - } else if (a_type == Lifetime) { - - // LIFETIME - if (a_length != sizeof(m_lifetime)) - return false; - stream >> m_lifetime; - m_attributes << Lifetime; - - } else if (a_type == Nonce) { - - // NONCE - m_nonce.resize(a_length); - stream.readRawData(m_nonce.data(), m_nonce.size()); - m_attributes << Nonce; - - } else if (a_type == Realm) { - - // REALM - QByteArray utf8Realm(a_length, 0); - stream.readRawData(utf8Realm.data(), utf8Realm.size()); - m_realm = QString::fromUtf8(utf8Realm); - m_attributes << Realm; - - } else if (a_type == RequestedTransport) { - - // REQUESTED-TRANSPORT - if (a_length != 4) - return false; - stream >> m_requestedTransport; - stream.skipRawData(3); - m_attributes << RequestedTransport; - - } else if (a_type == ReservationToken) { - - // RESERVATION-TOKEN - if (a_length != 8) - return false; - m_reservationToken.resize(a_length); - stream.readRawData(m_reservationToken.data(), m_reservationToken.size()); - m_attributes << ReservationToken; - - } else if (a_type == Software) { - - // SOFTWARE - QByteArray utf8Software(a_length, 0); - stream.readRawData(utf8Software.data(), utf8Software.size()); - m_software = QString::fromUtf8(utf8Software); - m_attributes << Software; - - } else if (a_type == Username) { - - // USERNAME - QByteArray utf8Username(a_length, 0); - stream.readRawData(utf8Username.data(), utf8Username.size()); - m_username = QString::fromUtf8(utf8Username); - m_attributes << Username; - - } else if (a_type == MappedAddress) { - - // MAPPED-ADDRESS - if (!decodeAddress(stream, a_length, mappedHost, mappedPort)) - { - *errors << QLatin1String("Bad MAPPED-ADDRESS"); - return false; - } - - } else if (a_type == ChangeRequest) { - - // CHANGE-REQUEST - if (a_length != sizeof(m_changeRequest)) - return false; - stream >> m_changeRequest; - m_attributes << ChangeRequest; - - } else if (a_type == SourceAddress) { - - // SOURCE-ADDRESS - if (!decodeAddress(stream, a_length, sourceHost, sourcePort)) - { - *errors << QLatin1String("Bad SOURCE-ADDRESS"); - return false; - } - - } else if (a_type == ChangedAddress) { - - // CHANGED-ADDRESS - if (!decodeAddress(stream, a_length, changedHost, changedPort)) - { - *errors << QLatin1String("Bad CHANGED-ADDRESS"); - return false; - } - - } else if (a_type == OtherAddress) { - - // OTHER-ADDRESS - if (!decodeAddress(stream, a_length, otherHost, otherPort)) - { - *errors << QLatin1String("Bad OTHER-ADDRESS"); - return false; - } - - } else if (a_type == XorMappedAddress) { - - // XOR-MAPPED-ADDRESS - if (!decodeAddress(stream, a_length, xorMappedHost, xorMappedPort, m_id)) - { - *errors << QLatin1String("Bad XOR-MAPPED-ADDRESS"); - return false; - } - - } else if (a_type == XorPeerAddress) { - - // XOR-PEER-ADDRESS - if (!decodeAddress(stream, a_length, xorPeerHost, xorPeerPort, m_id)) - { - *errors << QLatin1String("Bad XOR-PEER-ADDRESS"); - return false; - } - - } else if (a_type == XorRelayedAddress) { - - // XOR-RELAYED-ADDRESS - if (!decodeAddress(stream, a_length, xorRelayedHost, xorRelayedPort, m_id)) - { - *errors << QLatin1String("Bad XOR-RELAYED-ADDRESS"); - return false; - } - - } else if (a_type == MessageIntegrity) { - - // MESSAGE-INTEGRITY - if (a_length != 20) - return false; - QByteArray integrity(20, 0); - stream.readRawData(integrity.data(), integrity.size()); - - // check HMAC-SHA1 - if (!key.isEmpty()) - { - QByteArray copy = buffer.left(STUN_HEADER + done); - setBodyLength(copy, done + 24); - if (integrity != generateHmacSha1(key, copy)) - { - *errors << QLatin1String("Bad message integrity"); - return false; - } - } - - // from here onwards, only FINGERPRINT is allowed - after_integrity = true; - - } else if (a_type == Fingerprint) { - - // FINGERPRINT - if (a_length != 4) - return false; - quint32 fingerprint; - stream >> fingerprint; - - // check CRC32 - QByteArray copy = buffer.left(STUN_HEADER + done); - setBodyLength(copy, done + 8); - const quint32 expected = generateCrc32(copy) ^ 0x5354554eL; - if (fingerprint != expected) - { - *errors << QLatin1String("Bad fingerprint"); - return false; - } - - // stop parsing, no more attributes are allowed - return true; - - } else if (a_type == IceControlling) { - - /// ICE-CONTROLLING - if (a_length != 8) - return false; - iceControlling.resize(a_length); - stream.readRawData(iceControlling.data(), iceControlling.size()); - - } else if (a_type == IceControlled) { - - /// ICE-CONTROLLED - if (a_length != 8) - return false; - iceControlled.resize(a_length); - stream.readRawData(iceControlled.data(), iceControlled.size()); - - } else { - - // Unknown attribute - stream.skipRawData(a_length); - *errors << QString("Skipping unknown attribute %1").arg(QString::number(a_type)); - - } - stream.skipRawData(pad_length); - done += 4 + a_length + pad_length; - } - return true; -} - -/// Encodes the current QXmppStunMessage, optionally calculating the -/// message integrity attribute using the given key. -/// -/// \param key -/// \param addFingerprint - -QByteArray QXmppStunMessage::encode(const QByteArray &key, bool addFingerprint) const -{ - QByteArray buffer; - QDataStream stream(&buffer, QIODevice::WriteOnly); - - // encode STUN header - quint16 length = 0; - stream << m_type; - stream << length; - stream << m_cookie; - stream.writeRawData(m_id.data(), m_id.size()); - - // MAPPED-ADDRESS - addAddress(stream, MappedAddress, mappedHost, mappedPort); - - // CHANGE-REQUEST - if (m_attributes.contains(ChangeRequest)) { - stream << quint16(ChangeRequest); - stream << quint16(sizeof(m_changeRequest)); - stream << m_changeRequest; - } - - // SOURCE-ADDRESS - addAddress(stream, SourceAddress, sourceHost, sourcePort); - - // CHANGED-ADDRESS - addAddress(stream, ChangedAddress, changedHost, changedPort); - - // OTHER-ADDRESS - addAddress(stream, OtherAddress, otherHost, otherPort); - - // XOR-MAPPED-ADDRESS - addAddress(stream, XorMappedAddress, xorMappedHost, xorMappedPort, m_id); - - // XOR-PEER-ADDRESS - addAddress(stream, XorPeerAddress, xorPeerHost, xorPeerPort, m_id); - - // XOR-RELAYED-ADDRESS - addAddress(stream, XorRelayedAddress, xorRelayedHost, xorRelayedPort, m_id); - - // ERROR-CODE - if (errorCode) - { - const quint16 reserved = 0; - const quint8 errorCodeHigh = errorCode / 100; - const quint8 errorCodeLow = errorCode % 100; - const QByteArray phrase = errorPhrase.toUtf8(); - stream << quint16(ErrorCode); - stream << quint16(phrase.size() + 4); - stream << reserved; - stream << errorCodeHigh; - stream << errorCodeLow; - stream.writeRawData(phrase.data(), phrase.size()); - if (phrase.size() % 4) - { - const QByteArray padding(4 - (phrase.size() % 4), 0); - stream.writeRawData(padding.data(), padding.size()); - } - } - - // PRIORITY - if (m_attributes.contains(Priority)) - { - stream << quint16(Priority); - stream << quint16(sizeof(m_priority)); - stream << m_priority; - } - - // USE-CANDIDATE - if (useCandidate) - { - stream << quint16(UseCandidate); - stream << quint16(0); - } - - // CHANNEL-NUMBER - if (m_attributes.contains(ChannelNumber)) { - stream << quint16(ChannelNumber); - stream << quint16(4); - stream << m_channelNumber; - stream << quint16(0); - } - - // DATA - if (m_attributes.contains(DataAttr)) { - stream << quint16(DataAttr); - stream << quint16(m_data.size()); - stream.writeRawData(m_data.data(), m_data.size()); - if (m_data.size() % 4) { - const QByteArray padding(4 - (m_data.size() % 4), 0); - stream.writeRawData(padding.data(), padding.size()); - } - } - - // LIFETIME - if (m_attributes.contains(Lifetime)) { - stream << quint16(Lifetime); - stream << quint16(sizeof(m_lifetime)); - stream << m_lifetime; - } - - // NONCE - if (m_attributes.contains(Nonce)) { - stream << quint16(Nonce); - stream << quint16(m_nonce.size()); - stream.writeRawData(m_nonce.data(), m_nonce.size()); - } - - // REALM - if (m_attributes.contains(Realm)) - encodeString(stream, Realm, m_realm); - - // REQUESTED-TRANSPORT - if (m_attributes.contains(RequestedTransport)) { - const QByteArray reserved(3, 0); - stream << quint16(RequestedTransport); - stream << quint16(4); - stream << m_requestedTransport; - stream.writeRawData(reserved.data(), reserved.size()); - } - - // RESERVATION-TOKEN - if (m_attributes.contains(ReservationToken)) { - stream << quint16(ReservationToken); - stream << quint16(m_reservationToken.size()); - stream.writeRawData(m_reservationToken.data(), m_reservationToken.size()); - } - - // SOFTWARE - if (m_attributes.contains(Software)) - encodeString(stream, Software, m_software); - - // USERNAME - if (m_attributes.contains(Username)) - encodeString(stream, Username, m_username); - - // ICE-CONTROLLING or ICE-CONTROLLED - if (!iceControlling.isEmpty()) - { - stream << quint16(IceControlling); - stream << quint16(iceControlling.size()); - stream.writeRawData(iceControlling.data(), iceControlling.size()); - } else if (!iceControlled.isEmpty()) { - stream << quint16(IceControlled); - stream << quint16(iceControlled.size()); - stream.writeRawData(iceControlled.data(), iceControlled.size()); - } - - // set body length - setBodyLength(buffer, buffer.size() - STUN_HEADER); - - // MESSAGE-INTEGRITY - if (!key.isEmpty()) - { - setBodyLength(buffer, buffer.size() - STUN_HEADER + 24); - QByteArray integrity = generateHmacSha1(key, buffer); - stream << quint16(MessageIntegrity); - stream << quint16(integrity.size()); - stream.writeRawData(integrity.data(), integrity.size()); - } - - // FINGERPRINT - if (addFingerprint) - { - setBodyLength(buffer, buffer.size() - STUN_HEADER + 8); - quint32 fingerprint = generateCrc32(buffer) ^ 0x5354554eL; - stream << quint16(Fingerprint); - stream << quint16(sizeof(fingerprint)); - stream << fingerprint; - } - - return buffer; -} - -/// If the given packet looks like a STUN message, returns the message -/// type, otherwise returns 0. -/// -/// \param buffer -/// \param cookie -/// \param id - -quint16 QXmppStunMessage::peekType(const QByteArray &buffer, quint32 &cookie, QByteArray &id) -{ - if (buffer.size() < STUN_HEADER) - return 0; - - // parse STUN header - QDataStream stream(buffer); - quint16 type; - quint16 length; - stream >> type; - stream >> length; - stream >> cookie; - - if (length != buffer.size() - STUN_HEADER) - return 0; - - id.resize(ID_SIZE); - stream.readRawData(id.data(), id.size()); - return type; -} - -QString QXmppStunMessage::toString() const -{ - QStringList dumpLines; - QString typeName; - switch (messageMethod()) - { - case Binding: typeName = "Binding"; break; - case SharedSecret: typeName = "Shared Secret"; break; - case Allocate: typeName = "Allocate"; break; - case Refresh: typeName = "Refresh"; break; - case Send: typeName = "Send"; break; - case Data: typeName = "Data"; break; - case CreatePermission: typeName = "CreatePermission"; break; - case ChannelBind: typeName = "ChannelBind"; break; - default: typeName = "Unknown"; break; - } - switch (messageClass()) - { - case Request: typeName += " Request"; break; - case Indication: typeName += " Indication"; break; - case Response: typeName += " Response"; break; - case Error: typeName += " Error"; break; - default: break; - } - dumpLines << QString(" type %1 (%2)") - .arg(typeName) - .arg(QString::number(m_type)); - dumpLines << QString(" id %1").arg(QString::fromAscii(m_id.toHex())); - - // attributes - if (m_attributes.contains(ChannelNumber)) - dumpLines << QString(" * CHANNEL-NUMBER %1").arg(QString::number(m_channelNumber)); - if (errorCode) - dumpLines << QString(" * ERROR-CODE %1 %2") - .arg(QString::number(errorCode), errorPhrase); - if (m_attributes.contains(Lifetime)) - dumpLines << QString(" * LIFETIME %1").arg(QString::number(m_lifetime)); - if (m_attributes.contains(Nonce)) - dumpLines << QString(" * NONCE %1").arg(QString::fromLatin1(m_nonce)); - if (m_attributes.contains(Realm)) - dumpLines << QString(" * REALM %1").arg(m_realm); - if (m_attributes.contains(RequestedTransport)) - dumpLines << QString(" * REQUESTED-TRANSPORT 0x%1").arg(QString::number(m_requestedTransport, 16)); - if (m_attributes.contains(ReservationToken)) - dumpLines << QString(" * RESERVATION-TOKEN %1").arg(QString::fromAscii(m_reservationToken.toHex())); - if (m_attributes.contains(Software)) - dumpLines << QString(" * SOFTWARE %1").arg(m_software); - if (m_attributes.contains(Username)) - dumpLines << QString(" * USERNAME %1").arg(m_username); - if (mappedPort) - dumpLines << QString(" * MAPPED-ADDRESS %1 %2") - .arg(mappedHost.toString(), QString::number(mappedPort)); - if (m_attributes.contains(ChangeRequest)) - dumpLines << QString(" * CHANGE-REQUEST %1") - .arg(QString::number(m_changeRequest)); - if (sourcePort) - dumpLines << QString(" * SOURCE-ADDRESS %1 %2") - .arg(sourceHost.toString(), QString::number(sourcePort)); - if (changedPort) - dumpLines << QString(" * CHANGED-ADDRESS %1 %2") - .arg(changedHost.toString(), QString::number(changedPort)); - if (otherPort) - dumpLines << QString(" * OTHER-ADDRESS %1 %2") - .arg(otherHost.toString(), QString::number(otherPort)); - if (xorMappedPort) - dumpLines << QString(" * XOR-MAPPED-ADDRESS %1 %2") - .arg(xorMappedHost.toString(), QString::number(xorMappedPort)); - if (xorPeerPort) - dumpLines << QString(" * XOR-PEER-ADDRESS %1 %2") - .arg(xorPeerHost.toString(), QString::number(xorPeerPort)); - if (xorRelayedPort) - dumpLines << QString(" * XOR-RELAYED-ADDRESS %1 %2") - .arg(xorRelayedHost.toString(), QString::number(xorRelayedPort)); - if (m_attributes.contains(Priority)) - dumpLines << QString(" * PRIORITY %1").arg(QString::number(m_priority)); - if (!iceControlling.isEmpty()) - dumpLines << QString(" * ICE-CONTROLLING %1") - .arg(QString::fromAscii(iceControlling.toHex())); - if (!iceControlled.isEmpty()) - dumpLines << QString(" * ICE-CONTROLLED %1") - .arg(QString::fromAscii(iceControlled.toHex())); - - return dumpLines.join("\n"); -} - -/// Constructs a new QXmppStunTransaction. -/// -/// \param request -/// \param receiver - -QXmppStunTransaction::QXmppStunTransaction(const QXmppStunMessage &request, QObject *receiver) - : QXmppLoggable(receiver), - m_request(request), - m_tries(0) -{ - bool check; - Q_UNUSED(check); - - check = connect(this, SIGNAL(writeStun(QXmppStunMessage)), - receiver, SLOT(writeStun(QXmppStunMessage))); - Q_ASSERT(check); - - check = connect(this, SIGNAL(finished()), - receiver, SLOT(transactionFinished())); - Q_ASSERT(check); - - // RTO timer - m_retryTimer = new QTimer(this); - m_retryTimer->setSingleShot(true); - check = connect(m_retryTimer, SIGNAL(timeout()), - this, SLOT(retry())); - - // send packet immediately - m_tries++; - emit writeStun(m_request); - m_retryTimer->start(STUN_RTO_INTERVAL); -} - -void QXmppStunTransaction::readStun(const QXmppStunMessage &response) -{ - if (response.messageClass() == QXmppStunMessage::Error || - response.messageClass() == QXmppStunMessage::Response) { - m_response = response; - emit finished(); - } -} - -/// Returns the STUN request. - -QXmppStunMessage QXmppStunTransaction::request() const -{ - return m_request; -} - -/// Returns the STUN response. - -QXmppStunMessage QXmppStunTransaction::response() const -{ - return m_response; -} - -void QXmppStunTransaction::retry() -{ - if (m_tries >= STUN_RTO_MAX) { - m_response.setType(QXmppStunMessage::Error); - m_response.errorPhrase = QLatin1String("Request timed out"); - emit finished(); - return; - } - - // resend request - m_tries++; - emit writeStun(m_request); - m_retryTimer->start(2 * m_retryTimer->interval()); -} - -/// Constructs a new QXmppTurnAllocation. -/// -/// \param parent - -QXmppTurnAllocation::QXmppTurnAllocation(QObject *parent) - : QXmppLoggable(parent), - m_relayedPort(0), - m_turnPort(0), - m_channelNumber(0x4000), - m_lifetime(600), - m_state(UnconnectedState) -{ - bool check; - Q_UNUSED(check); - - socket = new QUdpSocket(this); - check = connect(socket, SIGNAL(readyRead()), - this, SLOT(readyRead())); - Q_ASSERT(check); - - m_timer = new QTimer(this); - m_timer->setSingleShot(true); - check = connect(m_timer, SIGNAL(timeout()), - this, SLOT(refresh())); - Q_ASSERT(check); - - // channels are valid 600s, we refresh every 500s - m_channelTimer = new QTimer(this); - m_channelTimer->setInterval(500 * 1000); - check = connect(m_channelTimer, SIGNAL(timeout()), - this, SLOT(refreshChannels())); - Q_ASSERT(check); -} - -/// Destroys the TURN allocation. - -QXmppTurnAllocation::~QXmppTurnAllocation() -{ - if (m_state == ConnectedState) - disconnectFromHost(); -} - -/// Allocates the TURN allocation. - -void QXmppTurnAllocation::connectToHost() -{ - if (m_state != UnconnectedState) - return; - - // start listening for UDP - if (socket->state() == QAbstractSocket::UnconnectedState) { - if (!socket->bind()) { - warning("Could not start listening for TURN"); - return; - } - } - - // send allocate request - QXmppStunMessage request; - request.setType(QXmppStunMessage::Allocate | QXmppStunMessage::Request); - request.setId(generateRandomBytes(12)); - request.setLifetime(m_lifetime); - request.setRequestedTransport(0x11); - m_transactions << new QXmppStunTransaction(request, this); - - // update state - setState(ConnectingState); -} - -/// Releases the TURN allocation. - -void QXmppTurnAllocation::disconnectFromHost() -{ - m_channelTimer->stop(); - m_timer->stop(); - - // clear channels and any outstanding transactions - m_channels.clear(); - foreach (QXmppStunTransaction *transaction, m_transactions) - delete transaction; - m_transactions.clear(); - - // end allocation - if (m_state == ConnectedState) { - QXmppStunMessage request; - request.setType(QXmppStunMessage::Refresh | QXmppStunMessage::Request); - request.setId(generateRandomBytes(12)); - request.setNonce(m_nonce); - request.setRealm(m_realm); - request.setUsername(m_username); - request.setLifetime(0); - m_transactions << new QXmppStunTransaction(request, this); - - setState(ClosingState); - } else { - setState(UnconnectedState); - } -} - -void QXmppTurnAllocation::readyRead() -{ - QByteArray buffer; - QHostAddress remoteHost; - quint16 remotePort; - while (socket->hasPendingDatagrams()) { - const qint64 size = socket->pendingDatagramSize(); - buffer.resize(size); - socket->readDatagram(buffer.data(), buffer.size(), &remoteHost, &remotePort); - handleDatagram(buffer, remoteHost, remotePort); - } -} - -void QXmppTurnAllocation::handleDatagram(const QByteArray &buffer, const QHostAddress &remoteHost, quint16 remotePort) -{ - // demultiplex channel data - if (buffer.size() >= 4 && (buffer[0] & 0xc0) == 0x40) { - QDataStream stream(buffer); - quint16 channel, length; - stream >> channel; - stream >> length; - if (m_state == ConnectedState && m_channels.contains(channel) && length <= buffer.size() - 4) { - emit datagramReceived(buffer.mid(4, length), m_channels[channel].first, - m_channels[channel].second); - } - return; - } - - // parse STUN message - QXmppStunMessage message; - QStringList errors; - if (!message.decode(buffer, QByteArray(), &errors)) { - foreach (const QString &error, errors) - warning(error); - return; - } - -#ifdef QXMPP_DEBUG_STUN - logReceived(QString("TURN packet from %1 port %2\n%3").arg( - remoteHost.toString(), - QString::number(remotePort), - message.toString())); -#endif - - // find transaction - foreach (QXmppStunTransaction *transaction, m_transactions) { - if (transaction->request().id() == message.id() && - transaction->request().messageMethod() == message.messageMethod()) { - transaction->readStun(message); - return; - } - } -} - -/// Refresh allocation. - -void QXmppTurnAllocation::refresh() -{ - QXmppStunMessage request; - request.setType(QXmppStunMessage::Refresh | QXmppStunMessage::Request); - request.setId(generateRandomBytes(12)); - request.setNonce(m_nonce); - request.setRealm(m_realm); - request.setUsername(m_username); - m_transactions << new QXmppStunTransaction(request, this); -} - -/// Refresh channel bindings. - -void QXmppTurnAllocation::refreshChannels() -{ - foreach (quint16 channel, m_channels.keys()) { - QXmppStunMessage request; - request.setType(QXmppStunMessage::ChannelBind | QXmppStunMessage::Request); - request.setId(generateRandomBytes(12)); - request.setNonce(m_nonce); - request.setRealm(m_realm); - request.setUsername(m_username); - request.setChannelNumber(channel); - request.xorPeerHost = m_channels[channel].first; - request.xorPeerPort = m_channels[channel].second; - m_transactions << new QXmppStunTransaction(request, this); - } -} - -/// Returns the relayed host address, i.e. the address on the server -/// used to communicate with peers. - -QHostAddress QXmppTurnAllocation::relayedHost() const -{ - return m_relayedHost; -} - -/// Returns the relayed port, i.e. the port on the server used to communicate -/// with peers. - -quint16 QXmppTurnAllocation::relayedPort() const -{ - return m_relayedPort; -} - -/// Sets the password used to authenticate with the TURN server. -/// -/// \param password - -void QXmppTurnAllocation::setPassword(const QString &password) -{ - m_password = password; -} - -/// Sets the TURN server to use. -/// -/// \param host The address of the TURN server. -/// \param port The port of the TURN server. - -void QXmppTurnAllocation::setServer(const QHostAddress &host, quint16 port) -{ - m_turnHost = host; - m_turnPort = port; -} - -/// Sets the \a user used for authentication with the TURN server. -/// -/// \param user - -void QXmppTurnAllocation::setUser(const QString &user) -{ - m_username = user; -} - -/// Returns the current state of the allocation. -/// - -QXmppTurnAllocation::AllocationState QXmppTurnAllocation::state() const -{ - return m_state; -} - -void QXmppTurnAllocation::setState(AllocationState state) -{ - if (state == m_state) - return; - m_state = state; - if (m_state == ConnectedState) { - emit connected(); - } else if (m_state == UnconnectedState) { - m_timer->stop(); - emit disconnected(); - } -} - -void QXmppTurnAllocation::transactionFinished() -{ - QXmppStunTransaction *transaction = qobject_cast(sender()); - if (!transaction || !m_transactions.removeAll(transaction)) - return; - transaction->deleteLater(); - - // handle authentication - const QXmppStunMessage reply = transaction->response(); - if (reply.messageClass() == QXmppStunMessage::Error && - reply.errorCode == 401 && - (reply.nonce() != m_nonce && reply.realm() != m_realm)) - { - // update long-term credentials - m_nonce = reply.nonce(); - m_realm = reply.realm(); - QCryptographicHash hash(QCryptographicHash::Md5); - hash.addData((m_username + ":" + m_realm + ":" + m_password).toUtf8()); - m_key = hash.result(); - - // retry request - QXmppStunMessage request(transaction->request()); - request.setId(generateRandomBytes(12)); - request.setNonce(m_nonce); - request.setRealm(m_realm); - request.setUsername(m_username); - m_transactions << new QXmppStunTransaction(request, this); - return; - } - - const quint16 method = transaction->request().messageMethod(); - if (method == QXmppStunMessage::Allocate) { - - if (reply.messageClass() == QXmppStunMessage::Error) { - warning(QString("Allocation failed: %1 %2").arg( - QString::number(reply.errorCode), reply.errorPhrase)); - setState(UnconnectedState); - return; - } - if (reply.xorRelayedHost.isNull() || - reply.xorRelayedHost.protocol() != QAbstractSocket::IPv4Protocol || - !reply.xorRelayedPort) { - warning("Allocation did not yield a valid relayed address"); - setState(UnconnectedState); - return; - } - - // store relayed address - m_relayedHost = reply.xorRelayedHost; - m_relayedPort = reply.xorRelayedPort; - - // schedule refresh - m_lifetime = reply.lifetime(); - m_timer->start((m_lifetime - 60) * 1000); - - setState(ConnectedState); - - } else if (method == QXmppStunMessage::ChannelBind) { - - if (reply.messageClass() == QXmppStunMessage::Error) { - warning(QString("ChannelBind failed: %1 %2").arg( - QString::number(reply.errorCode), reply.errorPhrase)); - - // remove channel - m_channels.remove(transaction->request().channelNumber()); - if (m_channels.isEmpty()) - m_channelTimer->stop(); - return; - } - - } else if (method == QXmppStunMessage::Refresh) { - - if (reply.messageClass() == QXmppStunMessage::Error) { - warning(QString("Refresh failed: %1 %2").arg( - QString::number(reply.errorCode), reply.errorPhrase)); - setState(UnconnectedState); - return; - } - - if (m_state == ClosingState) { - setState(UnconnectedState); - return; - } - - // schedule refresh - m_lifetime = reply.lifetime(); - m_timer->start((m_lifetime - 60) * 1000); - - } -} - -qint64 QXmppTurnAllocation::writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port) -{ - if (m_state != ConnectedState) - return -1; - - const Address addr = qMakePair(host, port); - quint16 channel = m_channels.key(addr); - - if (!channel) { - channel = m_channelNumber++; - m_channels.insert(channel, addr); - - // bind channel - QXmppStunMessage request; - request.setType(QXmppStunMessage::ChannelBind | QXmppStunMessage::Request); - request.setId(generateRandomBytes(12)); - request.setNonce(m_nonce); - request.setRealm(m_realm); - request.setUsername(m_username); - request.setChannelNumber(channel); - request.xorPeerHost = host; - request.xorPeerPort = port; - m_transactions << new QXmppStunTransaction(request, this); - - // schedule refresh - if (!m_channelTimer->isActive()) - m_channelTimer->start(); - } - - // send data - QByteArray channelData; - channelData.reserve(4 + data.size()); - QDataStream stream(&channelData, QIODevice::WriteOnly); - stream << channel; - stream << quint16(data.size()); - stream.writeRawData(data.data(), data.size()); - if (socket->writeDatagram(channelData, m_turnHost, m_turnPort) == channelData.size()) - return data.size(); - else - return -1; -} - -void QXmppTurnAllocation::writeStun(const QXmppStunMessage &message) -{ - socket->writeDatagram(message.encode(m_key), m_turnHost, m_turnPort); -#ifdef QXMPP_DEBUG_STUN - logSent(QString("TURN packet to %1 port %2\n%3").arg( - m_turnHost.toString(), - QString::number(m_turnPort), - message.toString())); -#endif -} - -QXmppIceComponent::Pair::Pair(int component, bool controlling) - : checked(QIODevice::NotOpen), - socket(0), - m_component(component), - m_controlling(controlling) -{ - transaction = generateRandomBytes(ID_SIZE); -} - -quint64 QXmppIceComponent::Pair::priority() const -{ - QXmppJingleCandidate local; - local.setComponent(m_component); - local.setType(socket ? QXmppJingleCandidate::HostType : QXmppJingleCandidate::RelayedType); - local.setPriority(candidatePriority(local)); - - // see RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs - const quint32 G = m_controlling ? local.priority() : remote.priority(); - const quint32 D = m_controlling ? remote.priority() : local.priority(); - return (quint64(1) << 32) * qMin(G, D) + 2 * qMax(G, D) + (G > D ? 1 : 0); -} - -QString QXmppIceComponent::Pair::toString() const -{ - QString str = QString("%1 port %2").arg(remote.host().toString(), QString::number(remote.port())); - if (socket) - str += QString(" (local %1 port %2)").arg(socket->localAddress().toString(), QString::number(socket->localPort())); - else - str += QString(" (relayed)"); - if (!reflexive.host().isNull() && reflexive.port()) - str += QString(" (reflexive %1 port %2)").arg(reflexive.host().toString(), QString::number(reflexive.port())); - return str; -} - -/// Constructs a new QXmppIceComponent. -/// -/// \param controlling -/// \param parent - -QXmppIceComponent::QXmppIceComponent(QObject *parent) - : QXmppLoggable(parent), - m_component(0), - m_activePair(0), - m_fallbackPair(0), - m_iceControlling(false), - m_peerReflexivePriority(0), - m_stunPort(0), - m_stunTries(0), - m_turnConfigured(false) -{ - bool check; - Q_UNUSED(check); - - m_localUser = generateStanzaHash(4); - m_localPassword = generateStanzaHash(22); - - m_timer = new QTimer(this); - m_timer->setInterval(500); - check = connect(m_timer, SIGNAL(timeout()), - this, SLOT(checkCandidates())); - Q_ASSERT(check); - - m_stunTimer = new QTimer(this); - m_stunTimer->setInterval(500); - check = connect(m_stunTimer, SIGNAL(timeout()), - this, SLOT(checkStun())); - Q_ASSERT(check); - - m_turnAllocation = new QXmppTurnAllocation(this); - check = connect(m_turnAllocation, SIGNAL(connected()), - this, SLOT(turnConnected())); - Q_ASSERT(check); - check = connect(m_turnAllocation, SIGNAL(datagramReceived(QByteArray,QHostAddress,quint16)), - this, SLOT(handleDatagram(QByteArray,QHostAddress,quint16))); - Q_ASSERT(check); -} - -/// Destroys the QXmppIceComponent. - -QXmppIceComponent::~QXmppIceComponent() -{ - foreach (Pair *pair, m_pairs) - delete pair; -} - -/// Returns the component id for the current socket, e.g. 1 for RTP -/// and 2 for RTCP. - -int QXmppIceComponent::component() const -{ - return m_component; -} - -/// Sets the component id for the current socket, e.g. 1 for RTP -/// and 2 for RTCP. -/// -/// \param component - -void QXmppIceComponent::setComponent(int component) -{ - m_component = component; - - // calculate peer-reflexive candidate priority - // see RFC 5245 - 7.1.2.1. PRIORITY and USE-CANDIDATE - QXmppJingleCandidate reflexive; - reflexive.setComponent(m_component); - reflexive.setType(QXmppJingleCandidate::PeerReflexiveType); - m_peerReflexivePriority = candidatePriority(reflexive); - - setObjectName(QString("STUN(%1)").arg(QString::number(m_component))); -} - -void QXmppIceComponent::checkCandidates() -{ - debug("Checking remote candidates"); - foreach (Pair *pair, m_pairs) - { - if (m_remoteUser.isEmpty()) - continue; - - // send a binding request - QXmppStunMessage message; - message.setId(pair->transaction); - message.setType(QXmppStunMessage::Binding | QXmppStunMessage::Request); - message.setPriority(m_peerReflexivePriority); - message.setUsername(QString("%1:%2").arg(m_remoteUser, m_localUser)); - if (m_iceControlling) - { - message.iceControlling = QByteArray(8, 0); - message.useCandidate = true; - } else { - message.iceControlled = QByteArray(8, 0); - } - writeStun(message, pair); - } - -} - -void QXmppIceComponent::checkStun() -{ - if (m_stunHost.isNull() || !m_stunPort || m_stunTries > 10) { - m_stunTimer->stop(); - return; - } - - // Send a request to STUN server to determine server-reflexive candidate - foreach (QUdpSocket *socket, m_sockets) - { - QXmppStunMessage msg; - msg.setType(QXmppStunMessage::Binding | QXmppStunMessage::Request); - msg.setId(m_stunId); -#ifdef QXMPP_DEBUG_STUN - logSent(QString("STUN packet to %1 port %2\n%3").arg(m_stunHost.toString(), - QString::number(m_stunPort), msg.toString())); -#endif - socket->writeDatagram(msg.encode(), m_stunHost, m_stunPort); - } - m_stunTries++; -} - -/// Stops ICE connectivity checks and closes the underlying sockets. - -void QXmppIceComponent::close() -{ - foreach (QUdpSocket *socket, m_sockets) - socket->close(); - m_turnAllocation->disconnectFromHost(); - m_timer->stop(); - m_stunTimer->stop(); - m_activePair = 0; -} - -/// Starts ICE connectivity checks. - -void QXmppIceComponent::connectToHost() -{ - if (m_activePair) - return; - - checkCandidates(); - m_timer->start(); -} - -/// Returns true if ICE negotiation completed, false otherwise. - -bool QXmppIceComponent::isConnected() const -{ - return m_activePair != 0; -} - -void QXmppIceComponent::setIceControlling(bool controlling) -{ - m_iceControlling = controlling; -} - -/// Returns the list of local candidates. - -QList QXmppIceComponent::localCandidates() const -{ - return m_localCandidates; -} - -/// Sets the local user fragment. -/// -/// \param user - -void QXmppIceComponent::setLocalUser(const QString &user) -{ - m_localUser = user; -} - -/// Sets the local password. -/// -/// \param password - -void QXmppIceComponent::setLocalPassword(const QString &password) -{ - m_localPassword = password; -} - -/// Adds a remote STUN candidate. - -bool QXmppIceComponent::addRemoteCandidate(const QXmppJingleCandidate &candidate) -{ - if (candidate.component() != m_component || - (candidate.type() != QXmppJingleCandidate::HostType && - candidate.type() != QXmppJingleCandidate::RelayedType && - candidate.type() != QXmppJingleCandidate::ServerReflexiveType) || - candidate.protocol() != "udp" || - (candidate.host().protocol() != QAbstractSocket::IPv4Protocol && - candidate.host().protocol() != QAbstractSocket::IPv6Protocol)) - return false; - - foreach (Pair *pair, m_pairs) - if (pair->remote.host() == candidate.host() && - pair->remote.port() == candidate.port()) - return false; - - foreach (QUdpSocket *socket, m_sockets) - { - // do not pair IPv4 with IPv6 or global with link-local addresses - if (socket->localAddress().protocol() != candidate.host().protocol() || - isIPv6LinkLocalAddress(socket->localAddress()) != isIPv6LinkLocalAddress(candidate.host())) - continue; - - Pair *pair = new Pair(m_component, m_iceControlling); - pair->remote = candidate; - if (isIPv6LinkLocalAddress(pair->remote.host())) - { - QHostAddress remoteHost = pair->remote.host(); - remoteHost.setScopeId(socket->localAddress().scopeId()); - pair->remote.setHost(remoteHost); - } - pair->socket = socket; - m_pairs << pair; - - if (!m_fallbackPair) - m_fallbackPair = pair; - } - - // only use relaying for IPv4 candidates - if (m_turnConfigured && candidate.host().protocol() == QAbstractSocket::IPv4Protocol) { - Pair *pair = new Pair(m_component, m_iceControlling); - pair->remote = candidate; - pair->socket = 0; - m_pairs << pair; - } - return true; -} - -/// Adds a discovered peer-reflexive STUN candidate. - -QXmppIceComponent::Pair *QXmppIceComponent::addRemoteCandidate(QUdpSocket *socket, const QHostAddress &host, quint16 port, quint32 priority) -{ - foreach (Pair *pair, m_pairs) - if (pair->remote.host() == host && - pair->remote.port() == port && - pair->socket == socket) - return pair; - - QXmppJingleCandidate candidate; - candidate.setComponent(m_component); - candidate.setHost(host); - candidate.setId(generateStanzaHash(10)); - candidate.setPort(port); - candidate.setPriority(priority); - candidate.setProtocol("udp"); - candidate.setType(QXmppJingleCandidate::PeerReflexiveType); - - Pair *pair = new Pair(m_component, m_iceControlling); - pair->remote = candidate; - pair->socket = socket; - m_pairs << pair; - - debug(QString("Added candidate %1").arg(pair->toString())); - return pair; -} - -/// Sets the remote user fragment. -/// -/// \param user - -void QXmppIceComponent::setRemoteUser(const QString &user) -{ - m_remoteUser = user; -} - -/// Sets the remote password. -/// -/// \param password - -void QXmppIceComponent::setRemotePassword(const QString &password) -{ - m_remotePassword = password; -} - -/// Sets the list of sockets to use for this component. -/// -/// \param sockets - -void QXmppIceComponent::setSockets(QList sockets) -{ - // clear previous candidates and sockets - m_localCandidates.clear(); - foreach (QUdpSocket *socket, m_sockets) - delete socket; - m_sockets.clear(); - - // store candidates - int foundation = 0; - foreach (QUdpSocket *socket, sockets) - { - socket->setParent(this); - connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); - - QXmppJingleCandidate candidate; - candidate.setComponent(m_component); - candidate.setFoundation(foundation++); - // remove scope ID from IPv6 non-link local addresses - QHostAddress addr(socket->localAddress()); - if (addr.protocol() == QAbstractSocket::IPv6Protocol && - !isIPv6LinkLocalAddress(addr)) { - addr.setScopeId(QString()); - } - candidate.setHost(addr); - candidate.setId(generateStanzaHash(10)); - candidate.setPort(socket->localPort()); - candidate.setProtocol("udp"); - candidate.setType(QXmppJingleCandidate::HostType); - candidate.setPriority(candidatePriority(candidate)); - - m_sockets << socket; - m_localCandidates << candidate; - } - - // start STUN checks - if (!m_stunHost.isNull() && m_stunPort) { - m_stunTries = 0; - checkStun(); - m_stunTimer->start(); - } - - // connect to TURN server - if (m_turnConfigured) - m_turnAllocation->connectToHost(); -} - -/// Sets the STUN server to use to determine server-reflexive addresses -/// and ports. -/// -/// \param host The address of the STUN server. -/// \param port The port of the STUN server. - -void QXmppIceComponent::setStunServer(const QHostAddress &host, quint16 port) -{ - m_stunHost = host; - m_stunPort = port; - m_stunId = generateRandomBytes(ID_SIZE); -} - -/// Sets the TURN server to use to relay packets in double-NAT configurations. -/// -/// \param host The address of the TURN server. -/// \param port The port of the TURN server. - -void QXmppIceComponent::setTurnServer(const QHostAddress &host, quint16 port) -{ - m_turnAllocation->setServer(host, port); - m_turnConfigured = !host.isNull() && port; -} - -/// Sets the \a user used for authentication with the TURN server. -/// -/// \param user - -void QXmppIceComponent::setTurnUser(const QString &user) -{ - m_turnAllocation->setUser(user); -} - -/// Sets the \a password used for authentication with the TURN server. -/// -/// \param password - -void QXmppIceComponent::setTurnPassword(const QString &password) -{ - m_turnAllocation->setPassword(password); -} - -void QXmppIceComponent::readyRead() -{ - QUdpSocket *socket = qobject_cast(sender()); - if (!socket) - return; - - QByteArray buffer; - QHostAddress remoteHost; - quint16 remotePort; - while (socket->hasPendingDatagrams()) { - const qint64 size = socket->pendingDatagramSize(); - buffer.resize(size); - socket->readDatagram(buffer.data(), buffer.size(), &remoteHost, &remotePort); - handleDatagram(buffer, remoteHost, remotePort, socket); - } -} - -void QXmppIceComponent::handleDatagram(const QByteArray &buffer, const QHostAddress &remoteHost, quint16 remotePort, QUdpSocket *socket) -{ - // if this is not a STUN message, emit it - quint32 messageCookie; - QByteArray messageId; - quint16 messageType = QXmppStunMessage::peekType(buffer, messageCookie, messageId); - if (!messageType || messageCookie != STUN_MAGIC) - { - // use this as an opportunity to flag a potential pair - foreach (Pair *pair, m_pairs) { - if (pair->remote.host() == remoteHost && - pair->remote.port() == remotePort) { - m_fallbackPair = pair; - break; - } - } - emit datagramReceived(buffer); - return; - } - - // determine password to use - QString messagePassword; - if (messageId != m_stunId) - { - messagePassword = (messageType & 0xFF00) ? m_remotePassword : m_localPassword; - if (messagePassword.isEmpty()) - return; - } - - // parse STUN message - QXmppStunMessage message; - QStringList errors; - if (!message.decode(buffer, messagePassword.toUtf8(), &errors)) - { - foreach (const QString &error, errors) - warning(error); - return; - } -#ifdef QXMPP_DEBUG_STUN - logReceived(QString("STUN packet from %1 port %2\n%3").arg( - remoteHost.toString(), - QString::number(remotePort), - message.toString())); -#endif - - // check how to handle message - if (message.id() == m_stunId) - { - m_stunTimer->stop(); - - // determine server-reflexive address - QHostAddress reflexiveHost; - quint16 reflexivePort = 0; - if (!message.xorMappedHost.isNull() && message.xorMappedPort != 0) - { - reflexiveHost = message.xorMappedHost; - reflexivePort = message.xorMappedPort; - } - else if (!message.mappedHost.isNull() && message.mappedPort != 0) - { - reflexiveHost = message.mappedHost; - reflexivePort = message.mappedPort; - } else { - warning("STUN server did not provide a reflexive address"); - return; - } - - // check whether this candidates is already known - foreach (const QXmppJingleCandidate &candidate, m_localCandidates) - { - if (candidate.host() == reflexiveHost && - candidate.port() == reflexivePort && - candidate.type() == QXmppJingleCandidate::ServerReflexiveType) - return; - } - - // add the new local candidate - debug(QString("Adding server-reflexive candidate %1 port %2").arg(reflexiveHost.toString(), QString::number(reflexivePort))); - QXmppJingleCandidate candidate; - candidate.setComponent(m_component); - candidate.setHost(reflexiveHost); - candidate.setId(generateStanzaHash(10)); - candidate.setPort(reflexivePort); - candidate.setProtocol("udp"); - candidate.setType(QXmppJingleCandidate::ServerReflexiveType); - candidate.setPriority(candidatePriority(candidate)); - m_localCandidates << candidate; - - emit localCandidatesChanged(); - return; - } - - // process message from peer - Pair *pair = 0; - if (message.type() == (QXmppStunMessage::Binding | QXmppStunMessage::Request)) - { - // add remote candidate - pair = addRemoteCandidate(socket, remoteHost, remotePort, message.priority()); - - // send a binding response - QXmppStunMessage response; - response.setId(message.id()); - response.setType(QXmppStunMessage::Binding | QXmppStunMessage::Response); - response.setUsername(message.username()); - response.xorMappedHost = pair->remote.host(); - response.xorMappedPort = pair->remote.port(); - writeStun(response, pair); - - // update state - if (m_iceControlling || message.useCandidate) - { - debug(QString("ICE reverse check complete %1").arg(pair->toString())); - pair->checked |= QIODevice::ReadOnly; - } - - if (!m_iceControlling && !m_activePair && !m_remoteUser.isEmpty()) - { - // send a triggered connectivity test - QXmppStunMessage message; - message.setId(pair->transaction); - message.setType(QXmppStunMessage::Binding | QXmppStunMessage::Request); - message.setPriority(m_peerReflexivePriority); - message.setUsername(QString("%1:%2").arg(m_remoteUser, m_localUser)); - message.iceControlled = QByteArray(8, 0); - writeStun(message, pair); - } - - } else if (message.type() == (QXmppStunMessage::Binding | QXmppStunMessage::Response)) { - - // find the pair for this transaction - foreach (Pair *ptr, m_pairs) - { - if (ptr->transaction == message.id()) - { - pair = ptr; - break; - } - } - if (!pair) - { - debug(QString("Unknown transaction %1").arg(QString::fromAscii(message.id().toHex()))); - return; - } - // store peer-reflexive address - pair->reflexive.setHost(message.xorMappedHost); - pair->reflexive.setPort(message.xorMappedPort); - -#if 0 - // send a binding indication - QXmppStunMessage indication; - indication.setId(generateRandomBytes(ID_SIZE)); - indication.setType(BindingIndication); - m_socket->writeStun(indication, pair); -#endif - - // outgoing media can flow - debug(QString("ICE forward check complete %1").arg(pair->toString())); - pair->checked |= QIODevice::WriteOnly; - } - - // signal completion - if (pair && pair->checked == QIODevice::ReadWrite) - { - m_timer->stop(); - if (!m_activePair || pair->priority() > m_activePair->priority()) { - info(QString("ICE pair selected %1 (priority: %2)").arg( - pair->toString(), QString::number(pair->priority()))); - const bool wasConnected = (m_activePair != 0); - m_activePair = pair; - if (!wasConnected) - emit connected(); - } - } -} - -void QXmppIceComponent::turnConnected() -{ - // add the new local candidate - debug(QString("Adding relayed candidate %1 port %2").arg( - m_turnAllocation->relayedHost().toString(), - QString::number(m_turnAllocation->relayedPort()))); - QXmppJingleCandidate candidate; - candidate.setComponent(m_component); - candidate.setHost(m_turnAllocation->relayedHost()); - candidate.setId(generateStanzaHash(10)); - candidate.setPort(m_turnAllocation->relayedPort()); - candidate.setProtocol("udp"); - candidate.setType(QXmppJingleCandidate::RelayedType); - candidate.setPriority(candidatePriority(candidate)); - m_localCandidates << candidate; - - emit localCandidatesChanged(); -} - -static QList reservePort(const QList &addresses, quint16 port, QObject *parent) -{ - QList sockets; - foreach (const QHostAddress &address, addresses) { - QUdpSocket *socket = new QUdpSocket(parent); - sockets << socket; - if (!socket->bind(address, port)) { - for (int i = 0; i < sockets.size(); ++i) - delete sockets[i]; - sockets.clear(); - break; - } - } - return sockets; -} - -/// Returns the list of local network addresses. - -QList QXmppIceComponent::discoverAddresses() -{ - QList addresses; - foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) - { - if (!(interface.flags() & QNetworkInterface::IsRunning) || - interface.flags() & QNetworkInterface::IsLoopBack) - continue; - - foreach (const QNetworkAddressEntry &entry, interface.addressEntries()) - { - QHostAddress ip = entry.ip(); - if ((ip.protocol() != QAbstractSocket::IPv4Protocol && - ip.protocol() != QAbstractSocket::IPv6Protocol) || - entry.netmask().isNull()) - continue; - -#ifdef Q_OS_MAC - // FIXME: on Mac OS X, sending IPv6 UDP packets fails - if (ip.protocol() == QAbstractSocket::IPv6Protocol) - continue; -#endif - - // FIXME: for now skip IPv6 link-local addresses, seems to upset - // clients such as empathy - if (isIPv6LinkLocalAddress(ip)) { - ip.setScopeId(interface.name()); - continue; - } - addresses << ip; - } - } - return addresses; -} - -/// Tries to bind \a count UDP sockets on each of the given \a addresses. -/// -/// The port numbers are chosen so that they are consecutive, starting at -/// an even port. This makes them suitable for RTP/RTCP sockets pairs. -/// -/// \param addresses The network address on which to bind the sockets. -/// \param count The number of ports to reserve. -/// \param parent The parent object for the sockets. - -QList QXmppIceComponent::reservePorts(const QList &addresses, int count, QObject *parent) -{ - QList sockets; - if (addresses.isEmpty() || !count) - return sockets; - - const int expectedSize = addresses.size() * count; - quint16 port = 49152; - while (sockets.size() != expectedSize) { - // reserve first port (even number) - if (port % 2) - port++; - QList socketChunk; - while (socketChunk.isEmpty() && port <= 65536 - count) { - socketChunk = reservePort(addresses, port, parent); - if (socketChunk.isEmpty()) - port += 2; - } - if (socketChunk.isEmpty()) - return sockets; - - // reserve other ports - sockets << socketChunk; - for (int i = 1; i < count; ++i) { - socketChunk = reservePort(addresses, ++port, parent); - if (socketChunk.isEmpty()) - break; - sockets << socketChunk; - } - - // cleanup if we failed - if (sockets.size() != expectedSize) { - for (int i = 0; i < sockets.size(); ++i) - delete sockets[i]; - sockets.clear(); - } - } - return sockets; -} - -/// Sends a data packet to the remote party. -/// -/// \param datagram - -qint64 QXmppIceComponent::sendDatagram(const QByteArray &datagram) -{ - Pair *pair = m_activePair ? m_activePair : m_fallbackPair; - if (!pair) - return -1; - if (pair->socket) - return pair->socket->writeDatagram(datagram, pair->remote.host(), pair->remote.port()); - else if (m_turnAllocation->state() == QXmppTurnAllocation::ConnectedState) - return m_turnAllocation->writeDatagram(datagram, pair->remote.host(), pair->remote.port()); - else - return -1; -} - -/// Sends a STUN packet to the remote party. - -qint64 QXmppIceComponent::writeStun(const QXmppStunMessage &message, QXmppIceComponent::Pair *pair) -{ - qint64 ret; - const QString messagePassword = (message.type() & 0xFF00) ? m_localPassword : m_remotePassword; - if (pair->socket) - ret = pair->socket->writeDatagram( - message.encode(messagePassword.toUtf8()), - pair->remote.host(), - pair->remote.port()); - else if (m_turnAllocation->state() == QXmppTurnAllocation::ConnectedState) - ret = m_turnAllocation->writeDatagram( - message.encode(messagePassword.toUtf8()), - pair->remote.host(), - pair->remote.port()); - else - return -1; -#ifdef QXMPP_DEBUG_STUN - logSent(QString("Sent to %1\n%2").arg(pair->toString(), message.toString())); -#endif - return ret; -} - -/// Constructs a new ICE connection. -/// -/// \param controlling -/// \param parent - -QXmppIceConnection::QXmppIceConnection(QObject *parent) - : QXmppLoggable(parent), - m_iceControlling(false), - m_stunPort(0) -{ - bool check; - - m_localUser = generateStanzaHash(4); - m_localPassword = generateStanzaHash(22); - - // timer to limit connection time to 30 seconds - m_connectTimer = new QTimer(this); - m_connectTimer->setInterval(30000); - m_connectTimer->setSingleShot(true); - check = connect(m_connectTimer, SIGNAL(timeout()), - this, SLOT(slotTimeout())); - Q_ASSERT(check); - Q_UNUSED(check); -} - -/// Returns the given component of this ICE connection. -/// -/// \param component - -QXmppIceComponent *QXmppIceConnection::component(int component) -{ - return m_components.value(component); -} - -/// Adds a component to this ICE connection, for instance 1 for RTP -/// or 2 for RTCP. -/// -/// \param component - -void QXmppIceConnection::addComponent(int component) -{ - bool check; - Q_UNUSED(check); - - if (m_components.contains(component)) - { - warning(QString("Already have component %1").arg(QString::number(component))); - return; - } - - QXmppIceComponent *socket = new QXmppIceComponent(this); - socket->setComponent(component); - socket->setIceControlling(m_iceControlling); - socket->setLocalUser(m_localUser); - socket->setLocalPassword(m_localPassword); - socket->setStunServer(m_stunHost, m_stunPort); - socket->setTurnServer(m_turnHost, m_turnPort); - socket->setTurnUser(m_turnUser); - socket->setTurnPassword(m_turnPassword); - - check = connect(socket, SIGNAL(localCandidatesChanged()), - this, SIGNAL(localCandidatesChanged())); - Q_ASSERT(check); - - check = connect(socket, SIGNAL(connected()), - this, SLOT(slotConnected())); - Q_ASSERT(check); - - m_components[component] = socket; -} - -/// Adds a candidate for one of the remote components. -/// -/// \param candidate - -void QXmppIceConnection::addRemoteCandidate(const QXmppJingleCandidate &candidate) -{ - QXmppIceComponent *socket = m_components.value(candidate.component()); - if (!socket) - { - warning(QString("Not adding candidate for unknown component %1").arg( - QString::number(candidate.component()))); - return; - } - socket->addRemoteCandidate(candidate); -} - -/// Binds the local sockets to the specified addresses. -/// -/// \param addresses The addresses on which to listen. - -bool QXmppIceConnection::bind(const QList &addresses) -{ - // reserve ports - QList sockets = QXmppIceComponent::reservePorts(addresses, m_components.size()); - if (sockets.isEmpty() && !addresses.isEmpty()) - return false; - - // assign sockets - QList keys = m_components.keys(); - qSort(keys); - int s = 0; - foreach (int k, keys) { - m_components[k]->setSockets(sockets.mid(s, addresses.size())); - s += addresses.size(); - } - - return true; -} - -/// Closes the ICE connection. - -void QXmppIceConnection::close() -{ - m_connectTimer->stop(); - foreach (QXmppIceComponent *socket, m_components.values()) - socket->close(); -} - -/// Starts ICE connectivity checks. - -void QXmppIceConnection::connectToHost() -{ - if (isConnected() || m_connectTimer->isActive()) - return; - - foreach (QXmppIceComponent *socket, m_components.values()) - socket->connectToHost(); - m_connectTimer->start(); -} - - -/// Returns true if ICE negotiation completed, false otherwise. - -bool QXmppIceConnection::isConnected() const -{ - foreach (QXmppIceComponent *socket, m_components.values()) - if (!socket->isConnected()) - return false; - return true; -} - -void QXmppIceConnection::setIceControlling(bool controlling) -{ - m_iceControlling = controlling; - foreach (QXmppIceComponent *socket, m_components.values()) - socket->setIceControlling(controlling); -} - -/// Returns the list of local HOST CANDIDATES candidates by iterating -/// over the available network interfaces. - -QList QXmppIceConnection::localCandidates() const -{ - QList candidates; - foreach (QXmppIceComponent *socket, m_components.values()) - candidates += socket->localCandidates(); - return candidates; -} - -/// Returns the local user fragment. - -QString QXmppIceConnection::localUser() const -{ - return m_localUser; -} - -/// Sets the local user fragment. -/// -/// You do not usually need to call this as one is automatically generated. -/// -/// \param user - -void QXmppIceConnection::setLocalUser(const QString &user) -{ - m_localUser = user; - foreach (QXmppIceComponent *socket, m_components.values()) - socket->setLocalUser(user); -} - -/// Returns the local password. - -QString QXmppIceConnection::localPassword() const -{ - return m_localPassword; -} - -/// Sets the local password. -/// -/// You do not usually need to call this as one is automatically generated. -/// -/// \param password - -void QXmppIceConnection::setLocalPassword(const QString &password) -{ - m_localPassword = password; - foreach (QXmppIceComponent *socket, m_components.values()) - socket->setLocalPassword(password); -} - -/// Sets the remote user fragment. -/// -/// \param user - -void QXmppIceConnection::setRemoteUser(const QString &user) -{ - foreach (QXmppIceComponent *socket, m_components.values()) - socket->setRemoteUser(user); -} - -/// Sets the remote password. -/// -/// \param password - -void QXmppIceConnection::setRemotePassword(const QString &password) -{ - foreach (QXmppIceComponent *socket, m_components.values()) - socket->setRemotePassword(password); -} - -/// Sets the STUN server to use to determine server-reflexive addresses -/// and ports. -/// -/// \param host The address of the STUN server. -/// \param port The port of the STUN server. - -void QXmppIceConnection::setStunServer(const QHostAddress &host, quint16 port) -{ - m_stunHost = host; - m_stunPort = port; - foreach (QXmppIceComponent *socket, m_components.values()) - socket->setStunServer(host, port); -} - -/// Sets the TURN server to use to relay packets in double-NAT configurations. -/// -/// \param host The address of the TURN server. -/// \param port The port of the TURN server. - -void QXmppIceConnection::setTurnServer(const QHostAddress &host, quint16 port) -{ - m_turnHost = host; - m_turnPort = port; - foreach (QXmppIceComponent *socket, m_components.values()) - socket->setTurnServer(host, port); -} - -/// Sets the \a user used for authentication with the TURN server. -/// -/// \param user - -void QXmppIceConnection::setTurnUser(const QString &user) -{ - m_turnUser = user; - foreach (QXmppIceComponent *socket, m_components.values()) - socket->setTurnUser(user); -} - -/// Sets the \a password used for authentication with the TURN server. -/// -/// \param password - -void QXmppIceConnection::setTurnPassword(const QString &password) -{ - m_turnPassword = password; - foreach (QXmppIceComponent *socket, m_components.values()) - socket->setTurnPassword(password); -} - -void QXmppIceConnection::slotConnected() -{ - foreach (QXmppIceComponent *socket, m_components.values()) - if (!socket->isConnected()) - return; - info(QString("ICE negotiation completed")); - m_connectTimer->stop(); - emit connected(); -} - -void QXmppIceConnection::slotTimeout() -{ - warning(QString("ICE negotiation timed out")); - foreach (QXmppIceComponent *socket, m_components.values()) - socket->close(); - emit disconnected(); -} - diff --git a/src/QXmppStun.h b/src/QXmppStun.h deleted file mode 100644 index 1792d3cb..00000000 --- a/src/QXmppStun.h +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPSTUN_H -#define QXMPPSTUN_H - -#include - -#include "QXmppLogger.h" -#include "QXmppJingleIq.h" - -class QDataStream; -class QUdpSocket; -class QTimer; - -/// \internal -/// -/// The QXmppStunMessage class represents a STUN message. -/// - -class QXmppStunMessage -{ -public: - enum MethodType { - Binding = 0x1, - SharedSecret = 0x2, - Allocate = 0x3, - Refresh = 0x4, - Send = 0x6, - Data = 0x7, - CreatePermission = 0x8, - ChannelBind = 0x9, - }; - - enum ClassType { - Request = 0x000, - Indication = 0x010, - Response = 0x100, - Error = 0x110, - }; - - QXmppStunMessage(); - - quint32 cookie() const; - void setCookie(quint32 cookie); - - QByteArray id() const; - void setId(const QByteArray &id); - - quint16 messageClass() const; - quint16 messageMethod() const; - - quint16 type() const; - void setType(quint16 type); - - // attributes - - quint32 changeRequest() const; - void setChangeRequest(quint32 changeRequest); - - quint16 channelNumber() const; - void setChannelNumber(quint16 channelNumber); - - QByteArray data() const; - void setData(const QByteArray &data); - - quint32 lifetime() const; - void setLifetime(quint32 changeRequest); - - QByteArray nonce() const; - void setNonce(const QByteArray &nonce); - - quint32 priority() const; - void setPriority(quint32 priority); - - QString realm() const; - void setRealm(const QString &realm); - - QByteArray reservationToken() const; - void setReservationToken(const QByteArray &reservationToken); - - quint8 requestedTransport() const; - void setRequestedTransport(quint8 requestedTransport); - - QString software() const; - void setSoftware(const QString &software); - - QString username() const; - void setUsername(const QString &username); - - QByteArray encode(const QByteArray &key = QByteArray(), bool addFingerprint = true) const; - bool decode(const QByteArray &buffer, const QByteArray &key = QByteArray(), QStringList *errors = 0); - QString toString() const; - static quint16 peekType(const QByteArray &buffer, quint32 &cookie, QByteArray &id); - - // attributes - int errorCode; - QString errorPhrase; - QByteArray iceControlling; - QByteArray iceControlled; - QHostAddress changedHost; - quint16 changedPort; - QHostAddress mappedHost; - quint16 mappedPort; - QHostAddress otherHost; - quint16 otherPort; - QHostAddress sourceHost; - quint16 sourcePort; - QHostAddress xorMappedHost; - quint16 xorMappedPort; - QHostAddress xorPeerHost; - quint16 xorPeerPort; - QHostAddress xorRelayedHost; - quint16 xorRelayedPort; - bool useCandidate; - -private: - quint32 m_cookie; - QByteArray m_id; - quint16 m_type; - - // attributes - QSet m_attributes; - quint32 m_changeRequest; - quint16 m_channelNumber; - QByteArray m_data; - quint32 m_lifetime; - QByteArray m_nonce; - quint32 m_priority; - QString m_realm; - quint8 m_requestedTransport; - QByteArray m_reservationToken; - QString m_software; - QString m_username; -}; - -/// \internal -/// -/// The QXmppStunTransaction class represents a STUN transaction. -/// - -class QXmppStunTransaction : public QXmppLoggable -{ - Q_OBJECT - -public: - QXmppStunTransaction(const QXmppStunMessage &request, QObject *parent); - QXmppStunMessage request() const; - QXmppStunMessage response() const; - -signals: - void finished(); - void writeStun(const QXmppStunMessage &request); - -public slots: - void readStun(const QXmppStunMessage &response); - -private slots: - void retry(); - -private: - QXmppStunMessage m_request; - QXmppStunMessage m_response; - QTimer *m_retryTimer; - int m_tries; -}; - -/// \internal -/// -/// The QXmppTurnAllocation class represents a TURN allocation as defined -/// by RFC 5766 Traversal Using Relays around NAT (TURN). -/// - -class QXmppTurnAllocation : public QXmppLoggable -{ - Q_OBJECT - -public: - enum AllocationState - { - UnconnectedState, - ConnectingState, - ConnectedState, - ClosingState, - }; - - QXmppTurnAllocation(QObject *parent = 0); - ~QXmppTurnAllocation(); - - QHostAddress relayedHost() const; - quint16 relayedPort() const; - AllocationState state() const; - - void setServer(const QHostAddress &host, quint16 port = 3478); - void setUser(const QString &user); - void setPassword(const QString &password); - - qint64 writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port); - -signals: - /// \brief This signal is emitted once TURN allocation succeeds. - void connected(); - - /// \brief This signal is emitted when a data packet is received. - void datagramReceived(const QByteArray &data, const QHostAddress &host, quint16 port); - - /// \brief This signal is emitted when TURN allocation fails. - void disconnected(); - -public slots: - void connectToHost(); - void disconnectFromHost(); - -private slots: - void readyRead(); - void refresh(); - void refreshChannels(); - void transactionFinished(); - void writeStun(const QXmppStunMessage &message); - -private: - void handleDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port); - void setState(AllocationState state); - - QUdpSocket *socket; - QTimer *m_timer; - QTimer *m_channelTimer; - QString m_password; - QString m_username; - QHostAddress m_relayedHost; - quint16 m_relayedPort; - QHostAddress m_turnHost; - quint16 m_turnPort; - - // channels - typedef QPair Address; - quint16 m_channelNumber; - QMap m_channels; - - // state - quint32 m_lifetime; - QByteArray m_key; - QString m_realm; - QByteArray m_nonce; - AllocationState m_state; - QList m_transactions; -}; - -/// \brief The QXmppIceComponent class represents a piece of a media stream -/// requiring a single transport address, as defined by RFC 5245 -/// (Interactive Connectivity Establishment). - -class QXmppIceComponent : public QXmppLoggable -{ - Q_OBJECT - -public: - QXmppIceComponent(QObject *parent=0); - ~QXmppIceComponent(); - void setIceControlling(bool controlling); - void setStunServer(const QHostAddress &host, quint16 port); - void setTurnServer(const QHostAddress &host, quint16 port); - void setTurnUser(const QString &user); - void setTurnPassword(const QString &password); - - QList localCandidates() const; - void setLocalUser(const QString &user); - void setLocalPassword(const QString &password); - - int component() const; - void setComponent(int component); - - bool addRemoteCandidate(const QXmppJingleCandidate &candidate); - void setRemoteUser(const QString &user); - void setRemotePassword(const QString &password); - - bool isConnected() const; - void setSockets(QList sockets); - - static QList discoverAddresses(); - static QList reservePorts(const QList &addresses, int count, QObject *parent = 0); - -public slots: - void close(); - void connectToHost(); - qint64 sendDatagram(const QByteArray &datagram); - -private slots: - void checkCandidates(); - void checkStun(); - void handleDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port, QUdpSocket *socket = 0); - void readyRead(); - void turnConnected(); - -signals: - /// \brief This signal is emitted once ICE negotiation succeeds. - void connected(); - - /// \brief This signal is emitted when a data packet is received. - void datagramReceived(const QByteArray &datagram); - - /// \brief This signal is emitted when the list of local candidates changes. - void localCandidatesChanged(); - -private: - class Pair { - public: - Pair(int component, bool controlling); - quint64 priority() const; - QString toString() const; - - QIODevice::OpenMode checked; - QXmppJingleCandidate remote; - QXmppJingleCandidate reflexive; - QByteArray transaction; - QUdpSocket *socket; - - private: - int m_component; - bool m_controlling; - }; - - Pair *addRemoteCandidate(QUdpSocket *socket, const QHostAddress &host, quint16 port, quint32 priority); - qint64 writeStun(const QXmppStunMessage &message, QXmppIceComponent::Pair *pair); - - int m_component; - - QList m_localCandidates; - QString m_localUser; - QString m_localPassword; - - Pair *m_activePair; - Pair *m_fallbackPair; - bool m_iceControlling; - QList m_pairs; - quint32 m_peerReflexivePriority; - QString m_remoteUser; - QString m_remotePassword; - - QList m_sockets; - QTimer *m_timer; - - // STUN server - QByteArray m_stunId; - QHostAddress m_stunHost; - quint16 m_stunPort; - QTimer *m_stunTimer; - int m_stunTries; - - // TURN server - QXmppTurnAllocation *m_turnAllocation; - bool m_turnConfigured; -}; - -/// \brief The QXmppIceConnection class represents a set of UDP sockets -/// capable of performing Interactive Connectivity Establishment (RFC 5245). -/// - -class QXmppIceConnection : public QXmppLoggable -{ - Q_OBJECT - -public: - QXmppIceConnection(QObject *parent = 0); - - QXmppIceComponent *component(int component); - void addComponent(int component); - void setIceControlling(bool controlling); - - QList localCandidates() const; - QString localUser() const; - void setLocalUser(const QString &user); - QString localPassword() const; - void setLocalPassword(const QString &password); - - void addRemoteCandidate(const QXmppJingleCandidate &candidate); - void setRemoteUser(const QString &user); - void setRemotePassword(const QString &password); - - void setStunServer(const QHostAddress &host, quint16 port = 3478); - void setTurnServer(const QHostAddress &host, quint16 port = 3478); - void setTurnUser(const QString &user); - void setTurnPassword(const QString &password); - - bool bind(const QList &addresses); - bool isConnected() const; - -signals: - /// \brief This signal is emitted once ICE negotiation succeeds. - void connected(); - - /// \brief This signal is emitted when ICE negotiation fails. - void disconnected(); - - /// \brief This signal is emitted when the list of local candidates changes. - void localCandidatesChanged(); - -public slots: - void close(); - void connectToHost(); - -private slots: - void slotConnected(); - void slotTimeout(); - -private: - QTimer *m_connectTimer; - bool m_iceControlling; - QMap m_components; - QString m_localUser; - QString m_localPassword; - QHostAddress m_stunHost; - quint16 m_stunPort; - QHostAddress m_turnHost; - quint16 m_turnPort; - QString m_turnUser; - QString m_turnPassword; -}; - -#endif diff --git a/src/QXmppUtils.cpp b/src/QXmppUtils.cpp deleted file mode 100644 index 1698582f..00000000 --- a/src/QXmppUtils.cpp +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "QXmppUtils.h" -#include "QXmppLogger.h" - -// adapted from public domain source by Ross Williams and Eric Durbin -// FIXME : is this valid for big-endian machines? -static quint32 crctable[256] = -{ - 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 -}; - -QDateTime datetimeFromString(const QString &str) -{ - QRegExp tzRe("(Z|([+-])([0-9]{2}):([0-9]{2}))"); - int tzPos = tzRe.indexIn(str, 19); - if (str.size() < 20 || tzPos < 0) - return QDateTime(); - - // process date and time - QDateTime dt = QDateTime::fromString(str.left(19), "yyyy-MM-ddThh:mm:ss"); - dt.setTimeSpec(Qt::UTC); - - // process milliseconds - if (tzPos > 20 && str.at(19) == '.') - { - QString millis = (str.mid(20, tzPos - 20) + "000").left(3); - dt = dt.addMSecs(millis.toInt()); - } - - // process time zone - if (tzRe.cap(1) != "Z") - { - int offset = tzRe.cap(3).toInt() * 3600 + tzRe.cap(4).toInt() * 60; - if (tzRe.cap(2) == "+") - dt = dt.addSecs(-offset); - else - dt = dt.addSecs(offset); - } - return dt; -} - -QString datetimeToString(const QDateTime &dt) -{ - QDateTime utc = dt.toUTC(); - if (utc.time().msec()) - return utc.toString("yyyy-MM-ddThh:mm:ss.zzzZ"); - else - return utc.toString("yyyy-MM-ddThh:mm:ssZ"); -} - -/// Parses a timezone offset (in seconds) from a string. -/// -/// \param str -/// - -int timezoneOffsetFromString(const QString &str) -{ - QRegExp tzRe("(Z|([+-])([0-9]{2}):([0-9]{2}))"); - if (!tzRe.exactMatch(str)) - return 0; - - // No offset from UTC - if (tzRe.cap(1) == "Z") - return 0; - - // Calculate offset - const int offset = tzRe.cap(3).toInt() * 3600 + - tzRe.cap(4).toInt() * 60; - if (tzRe.cap(2) == "-") - return -offset; - else - return offset; -} - -/// Serializes a timezone offset (in seconds) to a string. -/// -/// \param secs - -QString timezoneOffsetToString(int secs) -{ - if (!secs) - return QString::fromLatin1("Z"); - - const QTime tzoTime = QTime(0, 0, 0).addSecs(qAbs(secs)); - return (secs < 0 ? "-" : "+") + tzoTime.toString("hh:mm"); -} - -QString jidToDomain(const QString &jid) -{ - return jidToBareJid(jid).split("@").last(); -} - -QString jidToResource(const QString& jid) -{ - const int pos = jid.indexOf(QChar('/')); - if (pos < 0) - return QString(); - return jid.mid(pos+1); -} - -QString jidToUser(const QString &jid) -{ - const int pos = jid.indexOf(QChar('@')); - if (pos < 0) - return QString(); - return jid.left(pos); -} - -QString jidToBareJid(const QString& jid) -{ - const int pos = jid.indexOf(QChar('/')); - if (pos < 0) - return jid; - return jid.left(pos); -} - -quint32 generateCrc32(const QByteArray &in) -{ - quint32 result = 0xffffffff; - for(int n = 0; n < in.size(); ++n) - result = (result >> 8) ^ (crctable[(result & 0xff) ^ (quint8)in[n]]); - return result ^= 0xffffffff; -} - -static QByteArray generateHmac(QCryptographicHash::Algorithm algorithm, const QByteArray &key, const QByteArray &text) -{ - QCryptographicHash hasher(algorithm); - - const int B = 64; - QByteArray kpad = key + QByteArray(B - key.size(), 0); - - QByteArray ba; - for (int i = 0; i < B; ++i) - ba += kpad[i] ^ 0x5c; - - QByteArray tmp; - for (int i = 0; i < B; ++i) - tmp += kpad[i] ^ 0x36; - hasher.addData(tmp); - hasher.addData(text); - ba += hasher.result(); - - hasher.reset(); - hasher.addData(ba); - return hasher.result(); -} - -QByteArray generateHmacMd5(const QByteArray &key, const QByteArray &text) -{ - return generateHmac(QCryptographicHash::Md5, key, text); -} - -QByteArray generateHmacSha1(const QByteArray &key, const QByteArray &text) -{ - return generateHmac(QCryptographicHash::Sha1, key, text); -} - -/// Generates a random integer x between 0 and N-1. -/// -/// \param N - -int generateRandomInteger(int N) -{ - Q_ASSERT(N > 0 && N <= RAND_MAX); - int val; - while (N <= (val = qrand() / (RAND_MAX/N))) {}; - return val; -} - -/// Returns a random byte array of the specified size. -/// -/// \param length - -QByteArray generateRandomBytes(int length) -{ - QByteArray bytes(length, 'm'); - for (int i = 0; i < length; ++i) - bytes[i] = (char)generateRandomInteger(256); - return bytes; -} - -/// Returns a random alphanumerical string of the specified size. -/// -/// \param length - -QString generateStanzaHash(int length) -{ - const QString somechars = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - const int N = somechars.size(); - QString hashResult; - for ( int idx = 0; idx < length; ++idx ) - hashResult += somechars[generateRandomInteger(N)]; - return hashResult; -} - -void helperToXmlAddAttribute(QXmlStreamWriter* stream, const QString& name, - const QString& value) -{ - if(!value.isEmpty()) - stream->writeAttribute(name,value); -} - -void helperToXmlAddDomElement(QXmlStreamWriter* stream, const QDomElement& element, const QStringList &omitNamespaces) -{ - stream->writeStartElement(element.tagName()); - - /* attributes */ - QString xmlns = element.namespaceURI(); - if (!xmlns.isEmpty() && !omitNamespaces.contains(xmlns)) - stream->writeAttribute("xmlns", xmlns); - QDomNamedNodeMap attrs = element.attributes(); - for (int i = 0; i < attrs.size(); i++) - { - QDomAttr attr = attrs.item(i).toAttr(); - stream->writeAttribute(attr.name(), attr.value()); - } - - /* children */ - QDomNode childNode = element.firstChild(); - while (!childNode.isNull()) - { - if (childNode.isElement()) - { - helperToXmlAddDomElement(stream, childNode.toElement(), QStringList() << xmlns); - } else if (childNode.isText()) { - stream->writeCharacters(childNode.toText().data()); - } - childNode = childNode.nextSibling(); - } - stream->writeEndElement(); -} - -void helperToXmlAddTextElement(QXmlStreamWriter* stream, const QString& name, - const QString& value) -{ - if(!value.isEmpty()) - stream->writeTextElement( name, value); - else - stream->writeEmptyElement(name); -} - diff --git a/src/QXmppUtils.h b/src/QXmppUtils.h deleted file mode 100644 index 80d84240..00000000 --- a/src/QXmppUtils.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Authors: - * Manjeet Dahiya - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPUTILS_H -#define QXMPPUTILS_H - -// forward declarations of QXmlStream* classes will not work on Mac, we need to -// include the whole header. -// See http://lists.trolltech.com/qt-interest/2008-07/thread00798-0.html -// for an explanation. -#include - -class QByteArray; -class QDateTime; -class QDomElement; -class QString; -class QStringList; - -// XEP-0082: XMPP Date and Time Profiles -QDateTime datetimeFromString(const QString &str); -QString datetimeToString(const QDateTime &dt); -int timezoneOffsetFromString(const QString &str); -QString timezoneOffsetToString(int secs); - -QString jidToDomain(const QString& jid); -QString jidToResource(const QString& jid); -QString jidToUser(const QString& jid); -QString jidToBareJid(const QString& jid); - -quint32 generateCrc32(const QByteArray &input); -QByteArray generateHmacMd5(const QByteArray &key, const QByteArray &text); -QByteArray generateHmacSha1(const QByteArray &key, const QByteArray &text); -int generateRandomInteger(int N); -QByteArray generateRandomBytes(int length); -QString generateStanzaHash(int length=32); - -void helperToXmlAddAttribute(QXmlStreamWriter* stream, const QString& name, - const QString& value); -void helperToXmlAddDomElement(QXmlStreamWriter* stream, - const QDomElement& element, const QStringList &omitNamespaces); -void helperToXmlAddTextElement(QXmlStreamWriter* stream, const QString& name, - const QString& value); - -#endif // QXMPPUTILS_H diff --git a/src/QXmppVCardIq.cpp b/src/QXmppVCardIq.cpp deleted file mode 100644 index aaaf4554..00000000 --- a/src/QXmppVCardIq.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#include -#include - -#include "QXmppVCardIq.h" -#include "QXmppUtils.h" -#include "QXmppConstants.h" - -QString getImageType(const QByteArray &contents) -{ - if (contents.startsWith("\x89PNG\x0d\x0a\x1a\x0a")) - return "image/png"; - else if (contents.startsWith("\x8aMNG")) - return "video/x-mng"; - else if (contents.startsWith("GIF8")) - return "image/gif"; - else if (contents.startsWith("BM")) - return "image/bmp"; - else if (contents.contains("/* XPM */")) - return "image/x-xpm"; - else if (contents.contains("writeStartElement("vCard"); - writer->writeAttribute("xmlns", ns_vcard); - if (m_birthday.isValid()) - helperToXmlAddTextElement(writer, "BDAY", m_birthday.toString("yyyy-MM-dd")); - if (!m_email.isEmpty()) - { - writer->writeStartElement("EMAIL"); - writer->writeEmptyElement("INTERNET"); - helperToXmlAddTextElement(writer, "USERID", m_email); - writer->writeEndElement(); - } - if (!m_fullName.isEmpty()) - helperToXmlAddTextElement(writer, "FN", m_fullName); - if(!m_nickName.isEmpty()) - helperToXmlAddTextElement(writer, "NICKNAME", m_nickName); - if (!m_firstName.isEmpty() || - !m_lastName.isEmpty() || - !m_middleName.isEmpty()) - { - writer->writeStartElement("N"); - if (!m_firstName.isEmpty()) - helperToXmlAddTextElement(writer, "GIVEN", m_firstName); - if (!m_lastName.isEmpty()) - helperToXmlAddTextElement(writer, "FAMILY", m_lastName); - if (!m_middleName.isEmpty()) - helperToXmlAddTextElement(writer, "MIDDLE", m_middleName); - writer->writeEndElement(); - } - if (!m_url.isEmpty()) - helperToXmlAddTextElement(writer, "URL", m_url); - - if(!photo().isEmpty()) - { - writer->writeStartElement("PHOTO"); - QString photoType = m_photoType; - if (photoType.isEmpty()) - photoType = getImageType(m_photo); - helperToXmlAddTextElement(writer, "TYPE", photoType); - helperToXmlAddTextElement(writer, "BINVAL", m_photo.toBase64()); - writer->writeEndElement(); - } - - writer->writeEndElement(); -} - diff --git a/src/QXmppVCardIq.h b/src/QXmppVCardIq.h deleted file mode 100644 index 348c00fc..00000000 --- a/src/QXmppVCardIq.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Manjeet Dahiya - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - - -#ifndef QXMPPVCARDIQ_H -#define QXMPPVCARDIQ_H - -#include "QXmppIq.h" -#include -#include -#include - -class QImage; - -/// \brief Represents the XMPP vCard. -/// -/// The functions names are self explanatory. -/// Look at QXmppVCardManager and XEP-0054: vcard-temp for more details. -/// -/// There are many field of XMPP vCard which are not present in -/// this class. File a issue for the same. We will add the requested -/// field to this class. -/// - -class QXmppVCardIq : public QXmppIq -{ -public: - QXmppVCardIq(const QString& bareJid = ""); - - QDate birthday() const; - void setBirthday(const QDate &birthday); - - QString email() const; - void setEmail(const QString&); - - QString firstName() const; - void setFirstName(const QString&); - - QString fullName() const; - void setFullName(const QString&); - - QString lastName() const; - void setLastName(const QString&); - - QString middleName() const; - void setMiddleName(const QString&); - - QString nickName() const; - void setNickName(const QString&); - - QByteArray photo() const; - void setPhoto(const QByteArray&); - - QString photoType() const; - void setPhotoType(const QString &type); - - QString url() const; - void setUrl(const QString&); - - /// \cond - static bool isVCard(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement&); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QDate m_birthday; - QString m_email; - QString m_firstName; - QString m_fullName; - QString m_lastName; - QString m_middleName; - QString m_nickName; - QString m_url; - - // not as 64 base - QByteArray m_photo; - QString m_photoType; -}; - -#endif // QXMPPVCARDIQ_H diff --git a/src/QXmppVersionIq.cpp b/src/QXmppVersionIq.cpp deleted file mode 100644 index 358596b6..00000000 --- a/src/QXmppVersionIq.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#include - -#include "QXmppConstants.h" -#include "QXmppUtils.h" -#include "QXmppVersionIq.h" - -/// Returns the name of the software. -/// - -QString QXmppVersionIq::name() const -{ - return m_name; -} - -/// Sets the name of the software. -/// -/// \param name - -void QXmppVersionIq::setName(const QString &name) -{ - m_name = name; -} - -/// Returns the operating system. -/// - -QString QXmppVersionIq::os() const -{ - return m_os; -} - -/// Sets the operating system. -/// -/// \param os - -void QXmppVersionIq::setOs(const QString &os) -{ - m_os = os; -} - -/// Returns the software version. -/// - -QString QXmppVersionIq::version() const -{ - return m_version; -} - -/// Sets the software version. -/// -/// \param version - -void QXmppVersionIq::setVersion(const QString &version) -{ - m_version = version; -} - -bool QXmppVersionIq::isVersionIq(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - return queryElement.namespaceURI() == ns_version; -} - -void QXmppVersionIq::parseElementFromChild(const QDomElement &element) -{ - QDomElement queryElement = element.firstChildElement("query"); - m_name = queryElement.firstChildElement("name").text(); - m_os = queryElement.firstChildElement("os").text(); - m_version = queryElement.firstChildElement("version").text(); -} - -void QXmppVersionIq::toXmlElementFromChild(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("query"); - writer->writeAttribute("xmlns", ns_version); - - if (!m_name.isEmpty()) - helperToXmlAddTextElement(writer, "name", m_name); - - if (!m_os.isEmpty()) - helperToXmlAddTextElement(writer, "os", m_os); - - if (!m_version.isEmpty()) - helperToXmlAddTextElement(writer, "version", m_version); - - writer->writeEndElement(); -} - diff --git a/src/QXmppVersionIq.h b/src/QXmppVersionIq.h deleted file mode 100644 index 57a800e0..00000000 --- a/src/QXmppVersionIq.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2008-2011 The QXmpp developers - * - * Author: - * Jeremy Lainé - * - * Source: - * http://code.google.com/p/qxmpp - * - * This file is a part of QXmpp library. - * - * 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. - * - */ - -#ifndef QXMPPVERSIONIQ_H -#define QXMPPVERSIONIQ_H - -#include "QXmppIq.h" - -/// \brief The QXmppVersionIq class represents an IQ for conveying a software -/// version as defined by XEP-0092: Software Version. -/// -/// \ingroup Stanzas - -class QXmppVersionIq : public QXmppIq -{ -public: - QString name() const; - void setName(const QString &name); - - QString os() const; - void setOs(const QString &os); - - QString version() const; - void setVersion(const QString &version); - - /// \cond - static bool isVersionIq(const QDomElement &element); - /// \endcond - -protected: - /// \cond - void parseElementFromChild(const QDomElement &element); - void toXmlElementFromChild(QXmlStreamWriter *writer) const; - /// \endcond - -private: - QString m_name; - QString m_os; - QString m_version; -}; - -#endif diff --git a/src/base/QXmppArchiveIq.cpp b/src/base/QXmppArchiveIq.cpp new file mode 100644 index 00000000..e8bef8fc --- /dev/null +++ b/src/base/QXmppArchiveIq.cpp @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include "QXmppArchiveIq.h" +#include "QXmppUtils.h" + +static const char *ns_archive = "urn:xmpp:archive"; +static const char *ns_rsm = "http://jabber.org/protocol/rsm"; + +QXmppArchiveMessage::QXmppArchiveMessage() + : m_received(false) +{ +} + +/// Returns the archived message's body. + +QString QXmppArchiveMessage::body() const +{ + return m_body; +} + +/// Sets the archived message's body. +/// +/// \param body +void QXmppArchiveMessage::setBody(const QString &body) +{ + m_body = body; +} + +/// Returns the archived message's date. + +QDateTime QXmppArchiveMessage::date() const +{ + return m_date; +} + +//// Sets the archived message's date. +/// +/// \param date + +void QXmppArchiveMessage::setDate(const QDateTime &date) +{ + m_date = date; +} + +/// Returns true if the archived message was received, false if it was sent. + +bool QXmppArchiveMessage::isReceived() const +{ + return m_received; +} + +/// Set to true if the archived message was received, false if it was sent. +/// +/// \param isReceived + +void QXmppArchiveMessage::setReceived(bool isReceived) +{ + m_received = isReceived; +} + +QXmppArchiveChat::QXmppArchiveChat() + : m_version(0) +{ +} + +void QXmppArchiveChat::parse(const QDomElement &element) +{ + m_with = element.attribute("with"); + m_start = datetimeFromString(element.attribute("start")); + m_subject = element.attribute("subject"); + m_thread = element.attribute("thread"); + m_version = element.attribute("version").toInt(); + + QDomElement child = element.firstChildElement(); + while (!child.isNull()) + { + if ((child.tagName() == "from") || (child.tagName() == "to")) + { + QXmppArchiveMessage message; + message.setBody(child.firstChildElement("body").text()); + message.setDate(m_start.addSecs(child.attribute("secs").toInt())); + message.setReceived(child.tagName() == "from"); + m_messages << message; + } + child = child.nextSiblingElement(); + } +} + +void QXmppArchiveChat::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("chat"); + writer->writeAttribute("xmlns", ns_archive); + helperToXmlAddAttribute(writer, "with", m_with); + if (m_start.isValid()) + helperToXmlAddAttribute(writer, "start", datetimeToString(m_start)); + helperToXmlAddAttribute(writer, "subject", m_subject); + helperToXmlAddAttribute(writer, "thread", m_thread); + if (m_version) + helperToXmlAddAttribute(writer, "version", QString::number(m_version)); + foreach (const QXmppArchiveMessage &message, m_messages) + { + writer->writeStartElement(message.isReceived() ? "from" : "to"); + helperToXmlAddAttribute(writer, "secs", QString::number(m_start.secsTo(message.date()))); + writer->writeTextElement("body", message.body()); + writer->writeEndElement(); + } + writer->writeEndElement(); +} + +/// Returns the conversation's messages. + +QList QXmppArchiveChat::messages() const +{ + return m_messages; +} + +/// Sets the conversation's messages. + +void QXmppArchiveChat::setMessages(const QList &messages) +{ + m_messages = messages; +} + +/// Returns the start of this conversation. + +QDateTime QXmppArchiveChat::start() const +{ + return m_start; +} + +/// Sets the start of this conversation. + +void QXmppArchiveChat::setStart(const QDateTime &start) +{ + m_start = start; +} + +/// Returns the conversation's subject. + +QString QXmppArchiveChat::subject() const +{ + return m_subject; +} + +/// Sets the conversation's subject. + +void QXmppArchiveChat::setSubject(const QString &subject) +{ + m_subject = subject; +} + +/// Returns the conversation's thread. + +QString QXmppArchiveChat::thread() const +{ + return m_thread; +} + +/// Sets the conversation's thread. + +void QXmppArchiveChat::setThread(const QString &thread) +{ + m_thread = thread; +} + +/// Returns the conversation's version. + +int QXmppArchiveChat::version() const +{ + return m_version; +} + +/// Sets the conversation's version. + +void QXmppArchiveChat::setVersion(int version) +{ + m_version = version; +} + +/// Returns the JID of the remote party. + +QString QXmppArchiveChat::with() const +{ + return m_with; +} + +/// Sets the JID of the remote party. + +void QXmppArchiveChat::setWith(const QString &with) +{ + m_with = with; +} + +/// Returns the chat conversation carried by this IQ. + +QXmppArchiveChat QXmppArchiveChatIq::chat() const +{ + return m_chat; +} + +/// Sets the chat conversation carried by this IQ. + +void QXmppArchiveChatIq::setChat(const QXmppArchiveChat &chat) +{ + m_chat = chat; +} + +bool QXmppArchiveChatIq::isArchiveChatIq(const QDomElement &element) +{ + QDomElement chatElement = element.firstChildElement("chat"); + return !chatElement.attribute("with").isEmpty(); + //return (chatElement.namespaceURI() == ns_archive); +} + +void QXmppArchiveChatIq::parseElementFromChild(const QDomElement &element) +{ + m_chat.parse(element.firstChildElement("chat")); +} + +void QXmppArchiveChatIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + m_chat.toXml(writer); +} + +/// Constructs a QXmppArchiveListIq. + +QXmppArchiveListIq::QXmppArchiveListIq() + : QXmppIq(QXmppIq::Get), m_max(0) +{ +} + +/// Returns the list of chat conversations. + +QList QXmppArchiveListIq::chats() const +{ + return m_chats; +} + +/// Sets the list of chat conversations. + +void QXmppArchiveListIq::setChats(const QList &chats) +{ + m_chats = chats; +} + +/// Returns the maximum number of results. +/// + +int QXmppArchiveListIq::max() const +{ + return m_max; +} + +/// Sets the maximum number of results. +/// +/// \param max + +void QXmppArchiveListIq::setMax(int max) +{ + m_max = max; +} + +/// Returns the JID which archived conversations must match. +/// + +QString QXmppArchiveListIq::with() const +{ + return m_with; +} + +/// Sets the JID which archived conversations must match. +/// +/// \param with + +void QXmppArchiveListIq::setWith(const QString &with) +{ + m_with = with; +} + +/// Returns the start date/time for the archived conversations. +/// + +QDateTime QXmppArchiveListIq::start() const +{ + return m_start; +} + +/// Sets the start date/time for the archived conversations. +/// +/// \param start + +void QXmppArchiveListIq::setStart(const QDateTime &start) +{ + m_start = start; +} + +/// Returns the end date/time for the archived conversations. +/// + +QDateTime QXmppArchiveListIq::end() const +{ + return m_end; +} + +/// Sets the end date/time for the archived conversations. +/// +/// \param end + +void QXmppArchiveListIq::setEnd(const QDateTime &end) +{ + m_end = end; +} + +bool QXmppArchiveListIq::isArchiveListIq(const QDomElement &element) +{ + QDomElement listElement = element.firstChildElement("list"); + return (listElement.namespaceURI() == ns_archive); +} + +void QXmppArchiveListIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement listElement = element.firstChildElement("list"); + m_with = listElement.attribute("with"); + m_start = datetimeFromString(listElement.attribute("start")); + m_end = datetimeFromString(listElement.attribute("end")); + + QDomElement setElement = listElement.firstChildElement("set"); + if (setElement.namespaceURI() == ns_rsm) + m_max = setElement.firstChildElement("max").text().toInt(); + + QDomElement child = listElement.firstChildElement(); + while (!child.isNull()) + { + if (child.tagName() == "chat") + { + QXmppArchiveChat chat; + chat.parse(child); + m_chats << chat; + } + child = child.nextSiblingElement(); + } +} + +void QXmppArchiveListIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("list"); + writer->writeAttribute("xmlns", ns_archive); + if (!m_with.isEmpty()) + helperToXmlAddAttribute(writer, "with", m_with); + if (m_start.isValid()) + helperToXmlAddAttribute(writer, "start", datetimeToString(m_start)); + if (m_end.isValid()) + helperToXmlAddAttribute(writer, "end", datetimeToString(m_end)); + if (m_max > 0) + { + writer->writeStartElement("set"); + writer->writeAttribute("xmlns", ns_rsm); + helperToXmlAddTextElement(writer, "max", QString::number(m_max)); + writer->writeEndElement(); + } + foreach (const QXmppArchiveChat &chat, m_chats) + chat.toXml(writer); + writer->writeEndElement(); +} + +bool QXmppArchivePrefIq::isArchivePrefIq(const QDomElement &element) +{ + QDomElement prefElement = element.firstChildElement("pref"); + return (prefElement.namespaceURI() == ns_archive); +} + +void QXmppArchivePrefIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("pref"); + Q_UNUSED(queryElement); +} + +void QXmppArchivePrefIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("pref"); + writer->writeAttribute("xmlns", ns_archive); + writer->writeEndElement(); +} + +/// Returns the JID which archived conversations must match. +/// + +QString QXmppArchiveRemoveIq::with() const +{ + return m_with; +} + +/// Sets the JID which archived conversations must match. +/// +/// \param with + +void QXmppArchiveRemoveIq::setWith(const QString &with) +{ + m_with = with; +} + +/// Returns the start date/time for the archived conversations. +/// + +QDateTime QXmppArchiveRemoveIq::start() const +{ + return m_start; +} + +/// Sets the start date/time for the archived conversations. +/// +/// \param start + +void QXmppArchiveRemoveIq::setStart(const QDateTime &start) +{ + m_start = start; +} + +/// Returns the end date/time for the archived conversations. +/// + +QDateTime QXmppArchiveRemoveIq::end() const +{ + return m_end; +} + +/// Sets the end date/time for the archived conversations. +/// +/// \param end + +void QXmppArchiveRemoveIq::setEnd(const QDateTime &end) +{ + m_end = end; +} + +bool QXmppArchiveRemoveIq::isArchiveRemoveIq(const QDomElement &element) +{ + QDomElement retrieveElement = element.firstChildElement("remove"); + return (retrieveElement.namespaceURI() == ns_archive); +} + +void QXmppArchiveRemoveIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement listElement = element.firstChildElement("remove"); + m_with = listElement.attribute("with"); + m_start = datetimeFromString(listElement.attribute("start")); + m_end = datetimeFromString(listElement.attribute("end")); +} + +void QXmppArchiveRemoveIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("remove"); + writer->writeAttribute("xmlns", ns_archive); + if (!m_with.isEmpty()) + helperToXmlAddAttribute(writer, "with", m_with); + if (m_start.isValid()) + helperToXmlAddAttribute(writer, "start", datetimeToString(m_start)); + if (m_end.isValid()) + helperToXmlAddAttribute(writer, "end", datetimeToString(m_end)); + writer->writeEndElement(); +} + +QXmppArchiveRetrieveIq::QXmppArchiveRetrieveIq() + : QXmppIq(QXmppIq::Get), m_max(0) +{ +} + +/// Returns the maximum number of results. +/// + +int QXmppArchiveRetrieveIq::max() const +{ + return m_max; +} + +/// Sets the maximum number of results. +/// +/// \param max + +void QXmppArchiveRetrieveIq::setMax(int max) +{ + m_max = max; +} + +/// Returns the start date/time for the archived conversations. +/// + +QDateTime QXmppArchiveRetrieveIq::start() const +{ + return m_start; +} + +/// Sets the start date/time for the archived conversations. +/// +/// \param start + +void QXmppArchiveRetrieveIq::setStart(const QDateTime &start) +{ + m_start = start; +} + +/// Returns the JID which archived conversations must match. +/// + +QString QXmppArchiveRetrieveIq::with() const +{ + return m_with; +} + +/// Sets the JID which archived conversations must match. +/// +/// \param with + +void QXmppArchiveRetrieveIq::setWith(const QString &with) +{ + m_with = with; +} + +bool QXmppArchiveRetrieveIq::isArchiveRetrieveIq(const QDomElement &element) +{ + QDomElement retrieveElement = element.firstChildElement("retrieve"); + return (retrieveElement.namespaceURI() == ns_archive); +} + +void QXmppArchiveRetrieveIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement retrieveElement = element.firstChildElement("retrieve"); + m_with = retrieveElement.attribute("with"); + m_start = datetimeFromString(retrieveElement.attribute("start")); + QDomElement setElement = retrieveElement.firstChildElement("set"); + if (setElement.namespaceURI() == ns_rsm) + m_max = setElement.firstChildElement("max").text().toInt(); +} + +void QXmppArchiveRetrieveIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("retrieve"); + writer->writeAttribute("xmlns", ns_archive); + helperToXmlAddAttribute(writer, "with", m_with); + helperToXmlAddAttribute(writer, "start", datetimeToString(m_start)); + if (m_max > 0) + { + writer->writeStartElement("set"); + writer->writeAttribute("xmlns", ns_rsm); + helperToXmlAddTextElement(writer, "max", QString::number(m_max)); + writer->writeEndElement(); + } + writer->writeEndElement(); +} diff --git a/src/base/QXmppArchiveIq.h b/src/base/QXmppArchiveIq.h new file mode 100644 index 00000000..c0784891 --- /dev/null +++ b/src/base/QXmppArchiveIq.h @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPARCHIVEIQ_H +#define QXMPPARCHIVEIQ_H + +#include "QXmppIq.h" + +#include + +class QXmlStreamWriter; +class QDomElement; + +/// \brief The QXmppArchiveMessage represents an archived message +/// as defined by XEP-0136: Message Archiving. + +class QXmppArchiveMessage +{ +public: + QXmppArchiveMessage(); + + QString body() const; + void setBody(const QString &body); + + QDateTime date() const; + void setDate(const QDateTime &date); + + bool isReceived() const; + void setReceived(bool isReceived); + +private: + QString m_body; + QDateTime m_date; + bool m_received; +}; + +/// \brief The QXmppArchiveChat represents an archived conversation +/// as defined by XEP-0136: Message Archiving. + +class QXmppArchiveChat +{ +public: + QXmppArchiveChat(); + + QList messages() const; + void setMessages(const QList &messages); + + QDateTime start() const; + void setStart(const QDateTime &start); + + QString subject() const; + void setSubject(const QString &subject); + + QString thread() const; + void setThread(const QString &thread); + + int version() const; + void setVersion(int version); + + QString with() const; + void setWith(const QString &with); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QList m_messages; + QDateTime m_start; + QString m_subject; + QString m_thread; + int m_version; + QString m_with; +}; + +/// \brief Represents an archive chat as defined by XEP-0136: Message Archiving. +/// +/// It is used to get chat as a QXmppArchiveChat. +/// +/// \ingroup Stanzas + +class QXmppArchiveChatIq : public QXmppIq +{ +public: + QXmppArchiveChat chat() const; + void setChat(const QXmppArchiveChat &chat); + + /// \cond + static bool isArchiveChatIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QXmppArchiveChat m_chat; +}; + +/// \brief Represents an archive list as defined by XEP-0136: Message Archiving. +/// +/// \ingroup Stanzas + +class QXmppArchiveListIq : public QXmppIq +{ +public: + QXmppArchiveListIq(); + + QList chats() const; + void setChats(const QList &chats); + + int max() const; + void setMax(int max); + + QString with() const; + void setWith( const QString &with ); + + QDateTime start() const; + void setStart(const QDateTime &start ); + + QDateTime end() const; + void setEnd(const QDateTime &end ); + + /// \cond + static bool isArchiveListIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + int m_max; + QString m_with; + QDateTime m_start; + QDateTime m_end; + QList m_chats; +}; + +/// \brief Represents an archive remove IQ as defined by XEP-0136: Message Archiving. +/// +/// \ingroup Stanzas + +class QXmppArchiveRemoveIq : public QXmppIq +{ +public: + QString with() const; + void setWith( const QString &with ); + + QDateTime start() const; + void setStart(const QDateTime &start ); + + QDateTime end() const; + void setEnd(const QDateTime &end ); + + /// \cond + static bool isArchiveRemoveIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString m_with; + QDateTime m_start; + QDateTime m_end; +}; + +/// \brief Represents an archive retrieve IQ as defined by XEP-0136: Message Archiving. +/// +/// \ingroup Stanzas + +class QXmppArchiveRetrieveIq : public QXmppIq +{ +public: + QXmppArchiveRetrieveIq(); + + int max() const; + void setMax(int max); + + QDateTime start() const; + void setStart(const QDateTime &start); + + QString with() const; + void setWith(const QString &with); + + /// \cond + static bool isArchiveRetrieveIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + int m_max; + QString m_with; + QDateTime m_start; +}; + +/// \brief Represents an archive preference IQ as defined by XEP-0136: Message Archiving. +/// +/// \ingroup Stanzas + +class QXmppArchivePrefIq : public QXmppIq +{ +public: + /// \cond + static bool isArchivePrefIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond +}; + +#endif // QXMPPARCHIVEIQ_H diff --git a/src/base/QXmppBindIq.cpp b/src/base/QXmppBindIq.cpp new file mode 100644 index 00000000..f818e002 --- /dev/null +++ b/src/base/QXmppBindIq.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include +#include +#include + +#include "QXmppBindIq.h" +#include "QXmppUtils.h" +#include "QXmppConstants.h" + +/// Returns the bound JID. +/// + +QString QXmppBindIq::jid() const +{ + return m_jid; +} + +/// Sets the bound JID. +/// +/// \param jid + +void QXmppBindIq::setJid(const QString& jid) +{ + m_jid = jid; +} + +/// Returns the requested resource. +/// + +QString QXmppBindIq::resource() const +{ + return m_resource; +} + +/// Sets the requested resource. +/// +/// \param resource + +void QXmppBindIq::setResource(const QString& resource) +{ + m_resource = resource; +} + +bool QXmppBindIq::isBindIq(const QDomElement &element) +{ + QDomElement bindElement = element.firstChildElement("bind"); + return (bindElement.namespaceURI() == ns_bind); +} + +void QXmppBindIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement bindElement = element.firstChildElement("bind"); + m_jid = bindElement.firstChildElement("jid").text(); + m_resource = bindElement.firstChildElement("resource").text(); +} + +void QXmppBindIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("bind"); + writer->writeAttribute("xmlns", ns_bind); + if (!m_jid.isEmpty()) + helperToXmlAddTextElement(writer, "jid", m_jid); + if (!m_resource.isEmpty()) + helperToXmlAddTextElement(writer, "resource", m_resource); + writer->writeEndElement(); +} + diff --git a/src/base/QXmppBindIq.h b/src/base/QXmppBindIq.h new file mode 100644 index 00000000..0131510c --- /dev/null +++ b/src/base/QXmppBindIq.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPBINDIQ_H +#define QXMPPBINDIQ_H + +#include "QXmppIq.h" + +/// \brief The QXmppBindIq class represents an IQ used for resource +/// binding as defined by RFC 5921. +/// +/// \ingroup Stanzas + +class QXmppBindIq : public QXmppIq +{ +public: + QString jid() const; + void setJid(const QString&); + + QString resource() const; + void setResource(const QString&); + + /// \cond + static bool isBindIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString m_jid; + QString m_resource; +}; + +#endif // QXMPPBIND_H diff --git a/src/base/QXmppBookmarkSet.cpp b/src/base/QXmppBookmarkSet.cpp new file mode 100644 index 00000000..b418d498 --- /dev/null +++ b/src/base/QXmppBookmarkSet.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include "QXmppBookmarkSet.h" +#include "QXmppUtils.h" + +static const char *ns_bookmarks = "storage:bookmarks"; + +/// Constructs a new conference room bookmark. +/// + +QXmppBookmarkConference::QXmppBookmarkConference() + : m_autoJoin(false) +{ +} + +/// Returns whether the client should automatically join the conference room +/// on login. +/// + +bool QXmppBookmarkConference::autoJoin() const +{ + return m_autoJoin; +} + +/// Sets whether the client should automatically join the conference room +/// on login. +/// +/// \param autoJoin + +void QXmppBookmarkConference::setAutoJoin(bool autoJoin) +{ + m_autoJoin = autoJoin; +} + +/// Returns the JID of the conference room. +/// + +QString QXmppBookmarkConference::jid() const +{ + return m_jid; +} + +/// Sets the JID of the conference room. +/// +/// \param jid + +void QXmppBookmarkConference::setJid(const QString &jid) +{ + m_jid = jid; +} + +/// Returns the friendly name for the bookmark. +/// + +QString QXmppBookmarkConference::name() const +{ + return m_name; +} + +/// Sets the friendly name for the bookmark. +/// +/// \param name + +void QXmppBookmarkConference::setName(const QString &name) +{ + m_name = name; +} + +/// Returns the preferred nickname for the conference room. +/// + +QString QXmppBookmarkConference::nickName() const +{ + return m_nickName; +} + +/// Sets the preferred nickname for the conference room. +/// +/// \param nickName + +void QXmppBookmarkConference::setNickName(const QString &nickName) +{ + m_nickName = nickName; +} + +/// Returns the friendly name for the bookmark. +/// + +QString QXmppBookmarkUrl::name() const +{ + return m_name; +} + +/// Sets the friendly name for the bookmark. +/// +/// \param name + +void QXmppBookmarkUrl::setName(const QString &name) +{ + m_name = name; +} + +/// Returns the URL for the web page. +/// + +QUrl QXmppBookmarkUrl::url() const +{ + return m_url; +} + +/// Sets the URL for the web page. +/// +/// \param url + +void QXmppBookmarkUrl::setUrl(const QUrl &url) +{ + m_url = url; +} + +/// Returns the conference rooms bookmarks in this bookmark set. +/// + +QList QXmppBookmarkSet::conferences() const +{ + return m_conferences; +} + +/// Sets the conference rooms bookmarks in this bookmark set. +/// +/// \param conferences + +void QXmppBookmarkSet::setConferences(const QList &conferences) +{ + m_conferences = conferences; +} + +/// Returns the web page bookmarks in this bookmark set. +/// + +QList QXmppBookmarkSet::urls() const +{ + return m_urls; +} + +/// Sets the web page bookmarks in this bookmark set. +/// +/// \param urls + +void QXmppBookmarkSet::setUrls(const QList &urls) +{ + m_urls = urls; +} + +bool QXmppBookmarkSet::isBookmarkSet(const QDomElement &element) +{ + return element.tagName() == "storage" && + element.namespaceURI() == ns_bookmarks; +} + +void QXmppBookmarkSet::parse(const QDomElement &element) +{ + QDomElement childElement = element.firstChildElement(); + while (!childElement.isNull()) + { + if (childElement.tagName() == "conference") + { + QXmppBookmarkConference conference; + conference.setAutoJoin(childElement.attribute("autojoin") == "true"); + conference.setJid(childElement.attribute("jid")); + conference.setName(childElement.attribute("name")); + conference.setNickName(childElement.firstChildElement("nick").text()); + m_conferences << conference; + } + else if (childElement.tagName() == "url") + { + QXmppBookmarkUrl url; + url.setName(childElement.attribute("name")); + url.setUrl(childElement.attribute("url")); + m_urls << url; + } + childElement = childElement.nextSiblingElement(); + } +} + +void QXmppBookmarkSet::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("storage"); + writer->writeAttribute("xmlns", ns_bookmarks); + foreach (const QXmppBookmarkConference &conference, m_conferences) + { + writer->writeStartElement("conference"); + if (conference.autoJoin()) + helperToXmlAddAttribute(writer, "autojoin", "true"); + helperToXmlAddAttribute(writer, "jid", conference.jid()); + helperToXmlAddAttribute(writer, "name", conference.name()); + if (!conference.nickName().isEmpty()) + helperToXmlAddTextElement(writer, "nick", conference.nickName()); + writer->writeEndElement(); + } + foreach (const QXmppBookmarkUrl &url, m_urls) + { + writer->writeStartElement("url"); + helperToXmlAddAttribute(writer, "name", url.name()); + helperToXmlAddAttribute(writer, "url", url.url().toString()); + writer->writeEndElement(); + } + writer->writeEndElement(); +} + diff --git a/src/base/QXmppBookmarkSet.h b/src/base/QXmppBookmarkSet.h new file mode 100644 index 00000000..aa90f2cf --- /dev/null +++ b/src/base/QXmppBookmarkSet.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPBOOKMARKSET_H +#define QXMPPBOOKMARKSET_H + +#include +#include +#include +#include + +class QDomElement; + +/// \brief The QXmppBookmarkConference class represents a bookmark for a conference room, +/// as defined by XEP-0048: Bookmarks. +/// +class QXmppBookmarkConference +{ +public: + QXmppBookmarkConference(); + + bool autoJoin() const; + void setAutoJoin(bool autoJoin); + + QString jid() const; + void setJid(const QString &jid); + + QString name() const; + void setName(const QString &name); + + QString nickName() const; + void setNickName(const QString &nickName); + +private: + bool m_autoJoin; + QString m_jid; + QString m_name; + QString m_nickName; +}; + +/// \brief The QXmppBookmarkUrl class represents a bookmark for a web page, +/// as defined by XEP-0048: Bookmarks. +/// +class QXmppBookmarkUrl +{ +public: + QString name() const; + void setName(const QString &name); + + QUrl url() const; + void setUrl(const QUrl &url); + +private: + QString m_name; + QUrl m_url; +}; + +/// \brief The QXmppbookmarkSets class represents a set of bookmarks, as defined +/// by XEP-0048: Bookmarks. +/// +class QXmppBookmarkSet +{ +public: + QList conferences() const; + void setConferences(const QList &conferences); + + QList urls() const; + void setUrls(const QList &urls); + + /// \cond + static bool isBookmarkSet(const QDomElement &element); + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endconf + +private: + QList m_conferences; + QList m_urls; +}; + +#endif diff --git a/src/base/QXmppByteStreamIq.cpp b/src/base/QXmppByteStreamIq.cpp new file mode 100644 index 00000000..e1628e72 --- /dev/null +++ b/src/base/QXmppByteStreamIq.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include "QXmppByteStreamIq.h" +#include "QXmppConstants.h" +#include "QXmppUtils.h" + +QHostAddress QXmppByteStreamIq::StreamHost::host() const +{ + return m_host; +} + +void QXmppByteStreamIq::StreamHost::setHost(const QHostAddress &host) +{ + m_host = host; +} + +QString QXmppByteStreamIq::StreamHost::jid() const +{ + return m_jid; +} + +void QXmppByteStreamIq::StreamHost::setJid(const QString &jid) +{ + m_jid = jid; +} + +quint16 QXmppByteStreamIq::StreamHost::port() const +{ + return m_port; +} + +void QXmppByteStreamIq::StreamHost::setPort(quint16 port) +{ + m_port = port; +} + +QString QXmppByteStreamIq::StreamHost::zeroconf() const +{ + return m_zeroconf; +} + +void QXmppByteStreamIq::StreamHost::setZeroconf(const QString &zeroconf) +{ + m_zeroconf = zeroconf; +} + +QXmppByteStreamIq::Mode QXmppByteStreamIq::mode() const +{ + return m_mode; +} + +void QXmppByteStreamIq::setMode(QXmppByteStreamIq::Mode mode) +{ + m_mode = mode; +} + +QString QXmppByteStreamIq::sid() const +{ + return m_sid; +} + +void QXmppByteStreamIq::setSid(const QString &sid) +{ + m_sid = sid; +} + +QString QXmppByteStreamIq::activate() const +{ + return m_activate; +} + +void QXmppByteStreamIq::setActivate(const QString &activate) +{ + m_activate = activate; +} + +QList QXmppByteStreamIq::streamHosts() const +{ + return m_streamHosts; +} + +void QXmppByteStreamIq::setStreamHosts(const QList &streamHosts) +{ + m_streamHosts = streamHosts; +} + +QString QXmppByteStreamIq::streamHostUsed() const +{ + return m_streamHostUsed; +} + +void QXmppByteStreamIq::setStreamHostUsed(const QString &jid) +{ + m_streamHostUsed = jid; +} + +bool QXmppByteStreamIq::isByteStreamIq(const QDomElement &element) +{ + return element.firstChildElement("query").namespaceURI() == ns_bytestreams; +} + +void QXmppByteStreamIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + m_sid = queryElement.attribute("sid"); + const QString modeStr = queryElement.attribute("mode"); + if (modeStr == "tcp") + m_mode = Tcp; + else if (modeStr == "udp") + m_mode = Udp; + else + m_mode = None; + + QDomElement hostElement = queryElement.firstChildElement("streamhost"); + while (!hostElement.isNull()) + { + StreamHost streamHost; + streamHost.setHost(QHostAddress(hostElement.attribute("host"))); + streamHost.setJid(hostElement.attribute("jid")); + streamHost.setPort(hostElement.attribute("port").toInt()); + streamHost.setZeroconf(hostElement.attribute("zeroconf")); + m_streamHosts.append(streamHost); + + hostElement = hostElement.nextSiblingElement("streamhost"); + } + m_activate = queryElement.firstChildElement("activate").text(); + m_streamHostUsed = queryElement.firstChildElement("streamhost-used").attribute("jid"); +} + +void QXmppByteStreamIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("query"); + writer->writeAttribute("xmlns", ns_bytestreams); + helperToXmlAddAttribute(writer, "sid", m_sid); + QString modeStr; + if (m_mode == Tcp) + modeStr = "tcp"; + else if (m_mode == Udp) + modeStr = "udp"; + helperToXmlAddAttribute(writer, "mode", modeStr); + foreach (const StreamHost& streamHost, m_streamHosts) + { + writer->writeStartElement("streamhost"); + helperToXmlAddAttribute(writer, "host", streamHost.host().toString()); + helperToXmlAddAttribute(writer, "jid", streamHost.jid()); + helperToXmlAddAttribute(writer, "port", QString::number(streamHost.port())); + helperToXmlAddAttribute(writer, "zeroconf", streamHost.zeroconf()); + writer->writeEndElement(); + } + if (!m_activate.isEmpty()) + helperToXmlAddTextElement(writer, "activate", m_activate); + if (!m_streamHostUsed.isEmpty()) + { + writer->writeStartElement("streamhost-used"); + helperToXmlAddAttribute(writer, "jid", m_streamHostUsed); + writer->writeEndElement(); + } + + writer->writeEndElement(); +} diff --git a/src/base/QXmppByteStreamIq.h b/src/base/QXmppByteStreamIq.h new file mode 100644 index 00000000..604c12e5 --- /dev/null +++ b/src/base/QXmppByteStreamIq.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPBYTESTREAMIQ_H +#define QXMPPBYTESTREAMIQ_H + +#include "QXmppIq.h" + +#include + +class QDomElement; +class QXmlStreamWriter; + +class QXmppByteStreamIq : public QXmppIq +{ +public: + enum Mode { + None = 0, + Tcp, + Udp, + }; + + class StreamHost + { + public: + QString jid() const; + void setJid(const QString &jid); + + QHostAddress host() const; + void setHost(const QHostAddress &host); + + quint16 port() const; + void setPort(quint16 port); + + QString zeroconf() const; + void setZeroconf(const QString &zeroconf); + + private: + QHostAddress m_host; + QString m_jid; + quint16 m_port; + QString m_zeroconf; + }; + + QXmppByteStreamIq::Mode mode() const; + void setMode(QXmppByteStreamIq::Mode mode); + + QString sid() const; + void setSid(const QString &sid); + + QString activate() const; + void setActivate(const QString &activate); + + QList streamHosts() const; + void setStreamHosts(const QList &streamHosts); + + QString streamHostUsed() const; + void setStreamHostUsed(const QString &jid); + + static bool isByteStreamIq(const QDomElement &element); + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + Mode m_mode; + QString m_sid; + + QString m_activate; + QList m_streamHosts; + QString m_streamHostUsed; +}; + +#endif diff --git a/src/base/QXmppCodec.cpp b/src/base/QXmppCodec.cpp new file mode 100644 index 00000000..a614ce01 --- /dev/null +++ b/src/base/QXmppCodec.cpp @@ -0,0 +1,1218 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +/* + * G.711 based on reference implementation by Sun Microsystems, Inc. + */ + +#include +#include +#include + +#include "QXmppCodec.h" +#include "QXmppRtpChannel.h" + +#include + +#ifdef QXMPP_USE_SPEEX +#include +#endif + +#ifdef QXMPP_USE_THEORA +#include +#include +#endif + +#ifdef QXMPP_USE_VPX +#define VPX_CODEC_DISABLE_COMPAT 1 +#include +#include +#include +#include +#endif + +#define BIAS (0x84) /* Bias for linear code. */ +#define CLIP 8159 + +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define NSEGS (8) /* Number of A-law segments. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ + +enum FragmentType { + NoFragment = 0, + StartFragment, + MiddleFragment, + EndFragment, +}; + +static qint16 seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF, + 0x1FF, 0x3FF, 0x7FF, 0xFFF}; +static qint16 seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF, + 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; + +static qint16 search(qint16 val, qint16 *table, qint16 size) +{ + qint16 i; + + for (i = 0; i < size; i++) { + if (val <= *table++) + return (i); + } + return (size); +} + +/* + * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law + * + * Accepts a 16-bit integer and encodes it as A-law data. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +quint8 linear2alaw(qint16 pcm_val) +{ + qint16 mask; + qint16 seg; + quint8 aval; + + pcm_val = pcm_val >> 3; + + if (pcm_val >= 0) { + mask = 0xD5; /* sign (7th) bit = 1 */ + } else { + mask = 0x55; /* sign bit = 0 */ + pcm_val = -pcm_val - 1; + } + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_aend, 8); + + /* Combine the sign, segment, and quantization bits. */ + + if (seg >= 8) /* out of range, return maximum value. */ + return (quint8) (0x7F ^ mask); + else { + aval = (quint8) seg << SEG_SHIFT; + if (seg < 2) + aval |= (pcm_val >> 1) & QUANT_MASK; + else + aval |= (pcm_val >> seg) & QUANT_MASK; + return (aval ^ mask); + } +} + +/* + * alaw2linear() - Convert an A-law value to 16-bit linear PCM + * + */ +qint16 alaw2linear(quint8 a_val) +{ + qint16 t; + qint16 seg; + + a_val ^= 0x55; + + t = (a_val & QUANT_MASK) << 4; + seg = ((qint16)a_val & SEG_MASK) >> SEG_SHIFT; + switch (seg) { + case 0: + t += 8; + break; + case 1: + t += 0x108; + break; + default: + t += 0x108; + t <<= seg - 1; + } + return ((a_val & SIGN_BIT) ? t : -t); +} + +/* + * linear2ulaw() - Convert a linear PCM value to u-law + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +quint8 linear2ulaw(qint16 pcm_val) +{ + qint16 mask; + qint16 seg; + quint8 uval; + + /* Get the sign and the magnitude of the value. */ + pcm_val = pcm_val >> 2; + if (pcm_val < 0) { + pcm_val = -pcm_val; + mask = 0x7F; + } else { + mask = 0xFF; + } + if (pcm_val > CLIP) pcm_val = CLIP; /* clip the magnitude */ + pcm_val += (BIAS >> 2); + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_uend, 8); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + if (seg >= 8) /* out of range, return maximum value. */ + return (quint8) (0x7F ^ mask); + else { + uval = (quint8) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); + return (uval ^ mask); + } +} + +/* + * ulaw2linear() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +qint16 ulaw2linear(quint8 u_val) +{ + qint16 t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & QUANT_MASK) << 3) + BIAS; + t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; + + return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); +} + +QXmppG711aCodec::QXmppG711aCodec(int clockrate) +{ + m_frequency = clockrate; +} + +qint64 QXmppG711aCodec::encode(QDataStream &input, QDataStream &output) +{ + qint64 samples = 0; + qint16 pcm; + while (!input.atEnd()) + { + input >> pcm; + output << linear2alaw(pcm); + ++samples; + } + return samples; +} + +qint64 QXmppG711aCodec::decode(QDataStream &input, QDataStream &output) +{ + qint64 samples = 0; + quint8 g711; + while (!input.atEnd()) + { + input >> g711; + output << alaw2linear(g711); + ++samples; + } + return samples; +} + +QXmppG711uCodec::QXmppG711uCodec(int clockrate) +{ + m_frequency = clockrate; +} + +qint64 QXmppG711uCodec::encode(QDataStream &input, QDataStream &output) +{ + qint64 samples = 0; + qint16 pcm; + while (!input.atEnd()) + { + input >> pcm; + output << linear2ulaw(pcm); + ++samples; + } + return samples; +} + +qint64 QXmppG711uCodec::decode(QDataStream &input, QDataStream &output) +{ + qint64 samples = 0; + quint8 g711; + while (!input.atEnd()) + { + input >> g711; + output << ulaw2linear(g711); + ++samples; + } + return samples; +} + +#ifdef QXMPP_USE_SPEEX +QXmppSpeexCodec::QXmppSpeexCodec(int clockrate) +{ + const SpeexMode *mode = &speex_nb_mode; + if (clockrate == 32000) + mode = &speex_uwb_mode; + else if (clockrate == 16000) + mode = &speex_wb_mode; + else if (clockrate == 8000) + mode = &speex_nb_mode; + else + qWarning() << "QXmppSpeexCodec got invalid clockrate" << clockrate; + + // encoder + encoder_bits = new SpeexBits; + speex_bits_init(encoder_bits); + encoder_state = speex_encoder_init(mode); + + // decoder + decoder_bits = new SpeexBits; + speex_bits_init(decoder_bits); + decoder_state = speex_decoder_init(mode); + + // get frame size in samples + speex_encoder_ctl(encoder_state, SPEEX_GET_FRAME_SIZE, &frame_samples); +} + +QXmppSpeexCodec::~QXmppSpeexCodec() +{ + delete encoder_bits; + delete decoder_bits; +} + +qint64 QXmppSpeexCodec::encode(QDataStream &input, QDataStream &output) +{ + QByteArray pcm_buffer(frame_samples * 2, 0); + const int length = input.readRawData(pcm_buffer.data(), pcm_buffer.size()); + if (length != pcm_buffer.size()) + { + qWarning() << "Read only read" << length << "bytes"; + return 0; + } + speex_bits_reset(encoder_bits); + speex_encode_int(encoder_state, (short*)pcm_buffer.data(), encoder_bits); + QByteArray speex_buffer(speex_bits_nbytes(encoder_bits), 0); + speex_bits_write(encoder_bits, speex_buffer.data(), speex_buffer.size()); + output.writeRawData(speex_buffer.data(), speex_buffer.size()); + return frame_samples; +} + +qint64 QXmppSpeexCodec::decode(QDataStream &input, QDataStream &output) +{ + const int length = input.device()->bytesAvailable(); + QByteArray speex_buffer(length, 0); + input.readRawData(speex_buffer.data(), speex_buffer.size()); + speex_bits_read_from(decoder_bits, speex_buffer.data(), speex_buffer.size()); + QByteArray pcm_buffer(frame_samples * 2, 0); + speex_decode_int(decoder_state, decoder_bits, (short*)pcm_buffer.data()); + output.writeRawData(pcm_buffer.data(), pcm_buffer.size()); + return frame_samples; +} + +#endif + +#ifdef QXMPP_USE_THEORA + +class QXmppTheoraDecoderPrivate +{ +public: + bool decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame); + + th_comment comment; + th_info info; + th_setup_info *setup_info; + th_dec_ctx *ctx; + + QByteArray packetBuffer; +}; + +bool QXmppTheoraDecoderPrivate::decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame) +{ + if (!ctx) + return false; + + ogg_packet packet; + packet.packet = (unsigned char*) buffer.data(); + packet.bytes = buffer.size(); + packet.b_o_s = 1; + packet.e_o_s = 0; + packet.granulepos = -1; + packet.packetno = 0; + if (th_decode_packetin(ctx, &packet, 0) != 0) { + qWarning("Theora packet could not be decoded"); + return false; + } + + th_ycbcr_buffer ycbcr_buffer; + if (th_decode_ycbcr_out(ctx, ycbcr_buffer) != 0) { + qWarning("Theora packet has no Y'CbCr"); + return false; + } + + if (info.pixel_fmt == TH_PF_420) { + if (!frame->isValid()) { + const int bytes = ycbcr_buffer[0].stride * ycbcr_buffer[0].height + + ycbcr_buffer[1].stride * ycbcr_buffer[1].height + + ycbcr_buffer[2].stride * ycbcr_buffer[2].height; + + *frame = QXmppVideoFrame(bytes, + QSize(ycbcr_buffer[0].width, ycbcr_buffer[0].height), + ycbcr_buffer[0].stride, + QXmppVideoFrame::Format_YUV420P); + } + uchar *output = frame->bits(); + for (int i = 0; i < 3; ++i) { + const int length = ycbcr_buffer[i].stride * ycbcr_buffer[i].height; + memcpy(output, ycbcr_buffer[i].data, length); + output += length; + } + return true; + } else if (info.pixel_fmt == TH_PF_422) { + if (!frame->isValid()) { + const int bytes = ycbcr_buffer[0].width * ycbcr_buffer[0].height * 2; + + *frame = QXmppVideoFrame(bytes, + QSize(ycbcr_buffer[0].width, ycbcr_buffer[0].height), + ycbcr_buffer[0].width * 2, + QXmppVideoFrame::Format_YUYV); + } + + // YUV 4:2:2 packing + const int width = ycbcr_buffer[0].width; + const int height = ycbcr_buffer[0].height; + const int y_stride = ycbcr_buffer[0].stride; + const int c_stride = ycbcr_buffer[1].stride; + const uchar *y_row = ycbcr_buffer[0].data; + const uchar *cb_row = ycbcr_buffer[1].data; + const uchar *cr_row = ycbcr_buffer[2].data; + uchar *output = frame->bits(); + for (int y = 0; y < height; ++y) { + const uchar *y_ptr = y_row; + const uchar *cb_ptr = cb_row; + const uchar *cr_ptr = cr_row; + for (int x = 0; x < width; x += 2) { + *(output++) = *(y_ptr++); + *(output++) = *(cb_ptr++); + *(output++) = *(y_ptr++); + *(output++) = *(cr_ptr++); + } + y_row += y_stride; + cb_row += c_stride; + cr_row += c_stride; + } + return true; + } else { + qWarning("Theora decoder received an unsupported frame format"); + return false; + } +} + +QXmppTheoraDecoder::QXmppTheoraDecoder() +{ + d = new QXmppTheoraDecoderPrivate; + th_comment_init(&d->comment); + th_info_init(&d->info); + d->setup_info = 0; + d->ctx = 0; +} + +QXmppTheoraDecoder::~QXmppTheoraDecoder() +{ + th_comment_clear(&d->comment); + th_info_clear(&d->info); + if (d->setup_info) + th_setup_free(d->setup_info); + if (d->ctx) + th_decode_free(d->ctx); + delete d; +} + +QXmppVideoFormat QXmppTheoraDecoder::format() const +{ + QXmppVideoFormat format; + format.setFrameSize(QSize(d->info.frame_width, d->info.frame_height)); + if (d->info.pixel_fmt == TH_PF_420) + format.setPixelFormat(QXmppVideoFrame::Format_YUV420P); + else if (d->info.pixel_fmt == TH_PF_422) + format.setPixelFormat(QXmppVideoFrame::Format_YUYV); + else + format.setPixelFormat(QXmppVideoFrame::Format_Invalid); + if (d->info.fps_denominator > 0) + format.setFrameRate(qreal(d->info.fps_numerator) / qreal(d->info.fps_denominator)); + return format; +} + +QList QXmppTheoraDecoder::handlePacket(const QXmppRtpPacket &packet) +{ + QList frames; + + // theora deframing: draft-ietf-avt-rtp-theora-00 + QDataStream stream(packet.payload); + quint32 theora_header; + stream >> theora_header; + + quint32 theora_ident = (theora_header >> 8) & 0xffffff; + Q_UNUSED(theora_ident); + quint8 theora_frag = (theora_header & 0xc0) >> 6; + quint8 theora_type = (theora_header & 0x30) >> 4; + quint8 theora_packets = (theora_header & 0x0f); + + //qDebug("ident: 0x%08x, F: %d, TDT: %d, packets: %d", theora_ident, theora_frag, theora_type, theora_packets); + + // We only handle raw theora data + if (theora_type != 0) + return frames; + + QXmppVideoFrame frame; + quint16 packetLength; + + if (theora_frag == NoFragment) { + // unfragmented packet(s) + for (int i = 0; i < theora_packets; ++i) { + stream >> packetLength; + if (packetLength > stream.device()->bytesAvailable()) { + qWarning("Theora unfragmented packet has an invalid length"); + return frames; + } + + d->packetBuffer.resize(packetLength); + stream.readRawData(d->packetBuffer.data(), packetLength); + if (d->decodeFrame(d->packetBuffer, &frame)) + frames << frame; + d->packetBuffer.resize(0); + } + } else { + // fragments + stream >> packetLength; + if (packetLength > stream.device()->bytesAvailable()) { + qWarning("Theora packet has an invalid length"); + return frames; + } + + int pos; + if (theora_frag == StartFragment) { + // start fragment + pos = 0; + d->packetBuffer.resize(packetLength); + } else { + // continuation or end fragment + pos = d->packetBuffer.size(); + d->packetBuffer.resize(pos + packetLength); + } + stream.readRawData(d->packetBuffer.data() + pos, packetLength); + + if (theora_frag == EndFragment) { + // end fragment + if (d->decodeFrame(d->packetBuffer, &frame)) + frames << frame; + d->packetBuffer.resize(0); + } + } + return frames; +} + +bool QXmppTheoraDecoder::setParameters(const QMap ¶meters) +{ + QByteArray config = QByteArray::fromBase64(parameters.value("configuration").toAscii()); + QDataStream stream(config); + const QIODevice *device = stream.device(); + + if (device->bytesAvailable() < 4) { + qWarning("Theora configuration is too small"); + return false; + } + + // Process packed headers + int done = 0; + quint32 header_count; + stream >> header_count; + for (quint32 i = 0; i < header_count; ++i) { + if (device->bytesAvailable() < 6) { + qWarning("Theora configuration is too small"); + return false; + } + QByteArray ident(3, 0); + quint16 length; + quint8 h_count; + + stream.readRawData(ident.data(), ident.size()); + stream >> length; + stream >> h_count; +#ifdef QXMPP_DEBUG_THEORA + qDebug("Theora packed header %u ident=%s bytes=%u count=%u", i, ident.toHex().data(), length, h_count); +#endif + + // get header sizes + QList h_sizes; + for (int h = 0; h < h_count; ++h) { + quint16 h_size = 0; + quint8 b; + do { + if (device->bytesAvailable() < 1) { + qWarning("Theora configuration is too small"); + return false; + } + stream >> b; + h_size = (h_size << 7) | (b & 0x7f); + } while (b & 0x80); + h_sizes << h_size; +#ifdef QXMPP_DEBUG_THEORA + qDebug("Theora header %d size %u", h_sizes.size() - 1, h_sizes.last()); +#endif + length -= h_size; + } + h_sizes << length; +#ifdef QXMPP_DEBUG_THEORA + qDebug("Theora header %d size %u", h_sizes.size() - 1, h_sizes.last()); +#endif + + // decode headers + ogg_packet packet; + packet.b_o_s = 1; + packet.e_o_s = 0; + packet.granulepos = -1; + packet.packetno = 0; + + foreach (int h_size, h_sizes) { + if (device->bytesAvailable() < h_size) { + qWarning("Theora configuration is too small"); + return false; + } + + packet.packet = (unsigned char*) (config.data() + device->pos()); + packet.bytes = h_size; + int ret = th_decode_headerin(&d->info, &d->comment, &d->setup_info, &packet); + if (ret < 0) { + qWarning("Theora header could not be decoded"); + return false; + } + done += ret; + stream.skipRawData(h_size); + } + } + + // check for completion + if (done < 3) { + qWarning("Theora configuration did not contain enough headers"); + return false; + } + +#ifdef QXMPP_DEBUG_THEORA + qDebug("Theora frame_width %i, frame_height %i, colorspace %i, pixel_fmt: %i, target_bitrate: %i, quality: %i, keyframe_granule_shift: %i", + d->info.frame_width, + d->info.frame_height, + d->info.colorspace, + d->info.pixel_fmt, + d->info.target_bitrate, + d->info.quality, + d->info.keyframe_granule_shift); +#endif + if (d->info.pixel_fmt != TH_PF_420 && d->info.pixel_fmt != TH_PF_422) { + qWarning("Theora frames have an unsupported pixel format %d", d->info.pixel_fmt); + return false; + } + if (d->ctx) + th_decode_free(d->ctx); + d->ctx = th_decode_alloc(&d->info, d->setup_info); + if (!d->ctx) { + qWarning("Theora decoder could not be allocated"); + return false; + } + return true; +} + +class QXmppTheoraEncoderPrivate +{ +public: + void writeFragment(QDataStream &stream, FragmentType frag_type, quint8 theora_packets, const char *data, quint16 length); + + th_comment comment; + th_info info; + th_setup_info *setup_info; + th_enc_ctx *ctx; + th_ycbcr_buffer ycbcr_buffer; + + QByteArray buffer; + QByteArray configuration; + QByteArray ident; +}; + +void QXmppTheoraEncoderPrivate::writeFragment(QDataStream &stream, FragmentType frag_type, quint8 theora_packets, const char *data, quint16 length) +{ + // theora framing: draft-ietf-avt-rtp-theora-00 + const quint8 theora_type = 0; // raw data + stream.writeRawData(ident.constData(), ident.size()); + stream << quint8(((frag_type << 6) & 0xc0) | + ((theora_type << 4) & 0x30) | + (theora_packets & 0x0f)); + stream << quint16(length); + stream.writeRawData(data, length); +} + +QXmppTheoraEncoder::QXmppTheoraEncoder() +{ + d = new QXmppTheoraEncoderPrivate; + d->ident = QByteArray("\xc3\x45\xae"); + th_comment_init(&d->comment); + th_info_init(&d->info); + d->setup_info = 0; + d->ctx = 0; +} + +QXmppTheoraEncoder::~QXmppTheoraEncoder() +{ + th_comment_clear(&d->comment); + th_info_clear(&d->info); + if (d->setup_info) + th_setup_free(d->setup_info); + if (d->ctx) + th_encode_free(d->ctx); + delete d; +} + +bool QXmppTheoraEncoder::setFormat(const QXmppVideoFormat &format) +{ + const QXmppVideoFrame::PixelFormat pixelFormat = format.pixelFormat(); + if ((pixelFormat != QXmppVideoFrame::Format_YUV420P) && + (pixelFormat != QXmppVideoFrame::Format_YUYV)) { + qWarning("Theora encoder does not support the given format"); + return false; + } + + d->info.frame_width = format.frameSize().width(); + d->info.frame_height = format.frameSize().height(); + d->info.pic_height = format.frameSize().height(); + d->info.pic_width = format.frameSize().width(); + d->info.pic_x = 0; + d->info.pic_y = 0; + d->info.colorspace = TH_CS_UNSPECIFIED; + d->info.target_bitrate = 0; + d->info.quality = 48; + d->info.keyframe_granule_shift = 6; + + // FIXME: how do we handle floating point frame rates? + d->info.fps_numerator = format.frameRate(); + d->info.fps_denominator = 1; + + if (pixelFormat == QXmppVideoFrame::Format_YUV420P) { + d->info.pixel_fmt = TH_PF_420; + d->ycbcr_buffer[0].width = d->info.frame_width; + d->ycbcr_buffer[0].height = d->info.frame_height; + d->ycbcr_buffer[1].width = d->ycbcr_buffer[0].width / 2; + d->ycbcr_buffer[1].height = d->ycbcr_buffer[0].height / 2; + d->ycbcr_buffer[2].width = d->ycbcr_buffer[1].width; + d->ycbcr_buffer[2].height = d->ycbcr_buffer[1].height; + } else if (pixelFormat == QXmppVideoFrame::Format_YUYV) { + d->info.pixel_fmt = TH_PF_422; + d->buffer.resize(d->info.frame_width * d->info.frame_height * 2); + d->ycbcr_buffer[0].width = d->info.frame_width; + d->ycbcr_buffer[0].height = d->info.frame_height; + d->ycbcr_buffer[0].stride = d->info.frame_width; + d->ycbcr_buffer[0].data = (uchar*) d->buffer.data(); + d->ycbcr_buffer[1].width = d->ycbcr_buffer[0].width / 2; + d->ycbcr_buffer[1].height = d->ycbcr_buffer[0].height; + d->ycbcr_buffer[1].stride = d->ycbcr_buffer[0].stride / 2; + d->ycbcr_buffer[1].data = d->ycbcr_buffer[0].data + d->ycbcr_buffer[0].stride * d->ycbcr_buffer[0].height; + d->ycbcr_buffer[2].width = d->ycbcr_buffer[1].width; + d->ycbcr_buffer[2].height = d->ycbcr_buffer[1].height; + d->ycbcr_buffer[2].stride = d->ycbcr_buffer[1].stride; + d->ycbcr_buffer[2].data = d->ycbcr_buffer[1].data + d->ycbcr_buffer[1].stride * d->ycbcr_buffer[1].height; + } + + // create encoder + if (d->ctx) { + th_encode_free(d->ctx); + d->ctx = 0; + } + d->ctx = th_encode_alloc(&d->info); + if (!d->ctx) { + qWarning("Theora encoder could not be allocated"); + return false; + } + + // fetch headers + QList headers; + ogg_packet packet; + while (th_encode_flushheader(d->ctx, &d->comment, &packet) > 0) + headers << QByteArray((const char*)packet.packet, packet.bytes); + + // store configuration + d->configuration.clear(); + QDataStream stream(&d->configuration, QIODevice::WriteOnly); + stream << quint32(1); + + quint16 length = 0; + foreach (const QByteArray &header, headers) + length += header.size(); + + quint8 h_count = headers.size() - 1; + stream.writeRawData(d->ident.constData(), d->ident.size()); + stream << length; + stream << h_count; +#ifdef QXMPP_DEBUG_THEORA + qDebug("Theora packed header %u ident=%s bytes=%u count=%u", 0, d->ident.toHex().data(), length, h_count); +#endif + + // write header sizes + for (int h = 0; h < h_count; ++h) { + quint16 h_size = headers[h].size(); + do { + quint8 b = (h_size & 0x7f); + h_size >>= 7; + if (h_size) + b |= 0x80; + stream << b; + } while (h_size); + } + + // write headers + for (int h = 0; h < headers.size(); ++h) { +#ifdef QXMPP_DEBUG_THEORA + qDebug("Header %d size %d", h, headers[h].size()); +#endif + stream.writeRawData(headers[h].data(), headers[h].size()); + } + + return true; +} + +QList QXmppTheoraEncoder::handleFrame(const QXmppVideoFrame &frame) +{ + QList packets; + const int PACKET_MAX = 1388; + + if (!d->ctx) + return packets; + + if (d->info.pixel_fmt == TH_PF_420) { + d->ycbcr_buffer[0].stride = frame.bytesPerLine(); + d->ycbcr_buffer[0].data = (unsigned char*) frame.bits(); + d->ycbcr_buffer[1].stride = d->ycbcr_buffer[0].stride / 2; + d->ycbcr_buffer[1].data = d->ycbcr_buffer[0].data + d->ycbcr_buffer[0].stride * d->ycbcr_buffer[0].height; + d->ycbcr_buffer[2].stride = d->ycbcr_buffer[1].stride; + d->ycbcr_buffer[2].data = d->ycbcr_buffer[1].data + d->ycbcr_buffer[1].stride * d->ycbcr_buffer[1].height; + } else if (d->info.pixel_fmt == TH_PF_422) { + // YUV 4:2:2 unpacking + const int width = frame.width(); + const int height = frame.height(); + const int stride = frame.bytesPerLine(); + const uchar *row = frame.bits(); + uchar *y_out = d->ycbcr_buffer[0].data; + uchar *cb_out = d->ycbcr_buffer[1].data; + uchar *cr_out = d->ycbcr_buffer[2].data; + for (int y = 0; y < height; ++y) { + const uchar *ptr = row; + for (int x = 0; x < width; x += 2) { + *(y_out++) = *(ptr++); + *(cb_out++) = *(ptr++); + *(y_out++) = *(ptr++); + *(cr_out++) = *(ptr++); + } + row += stride; + } + } else { + qWarning("Theora encoder received an unsupported frame format"); + return packets; + } + + if (th_encode_ycbcr_in(d->ctx, d->ycbcr_buffer) != 0) { + qWarning("Theora encoder could not handle frame"); + return packets; + } + + QByteArray payload; + ogg_packet packet; + while (th_encode_packetout(d->ctx, 0, &packet) > 0) { +#ifdef QXMPP_DEBUG_THEORA + qDebug("Theora encoded packet %d bytes", packet.bytes); +#endif + QDataStream stream(&payload, QIODevice::WriteOnly); + const char *data = (const char*) packet.packet; + int size = packet.bytes; + if (size <= PACKET_MAX) { + // no fragmentation + stream.device()->reset(); + payload.resize(0); + d->writeFragment(stream, NoFragment, 1, data, size); + packets << payload; + } else { + // fragmentation + FragmentType frag_type = StartFragment; + while (size) { + const int length = qMin(PACKET_MAX, size); + stream.device()->reset(); + payload.resize(0); + d->writeFragment(stream, frag_type, 0, data, length); + data += length; + size -= length; + frag_type = (size > PACKET_MAX) ? MiddleFragment : EndFragment; + packets << payload; + } + } + } + + return packets; +} + +QMap QXmppTheoraEncoder::parameters() const +{ + QMap params; + if (d->ctx) { + params.insert("delivery-method", "inline"); + params.insert("configuration", d->configuration.toBase64()); + } + return params; +} + +#endif + +#ifdef QXMPP_USE_VPX + +class QXmppVpxDecoderPrivate +{ +public: + bool decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame); + + vpx_codec_ctx_t codec; + QByteArray packetBuffer; +}; + +bool QXmppVpxDecoderPrivate::decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame) +{ + if (vpx_codec_decode(&codec, (const uint8_t*)buffer.constData(), buffer.size(), NULL, 0) != VPX_CODEC_OK) { + qWarning("Vpx packet could not be decoded: %s", vpx_codec_error_detail(&codec)); + return false; + } + + vpx_codec_iter_t iter = NULL; + vpx_image_t *img; + while ((img = vpx_codec_get_frame(&codec, &iter))) { + if (img->fmt == VPX_IMG_FMT_I420) { + if (!frame->isValid()) { + const int bytes = img->d_w * img->d_h * 3 / 2; + + *frame = QXmppVideoFrame(bytes, + QSize(img->d_w, img->d_h), + img->d_w, + QXmppVideoFrame::Format_YUV420P); + } + uchar *output = frame->bits(); + + for (int i = 0; i < 3; ++i) { + uchar *input = img->planes[i]; + const int div = (i == 0) ? 1 : 2; + for (unsigned int y = 0; y < img->d_h / div; ++y) { + memcpy(output, input, img->d_w / div); + input += img->stride[i]; + output += img->d_w / div; + } + } + } else { + qWarning("Vpx decoder received an unsupported frame format: %d", img->fmt); + } + } + + return true; +} + +QXmppVpxDecoder::QXmppVpxDecoder() +{ + d = new QXmppVpxDecoderPrivate; + if (vpx_codec_dec_init(&d->codec, vpx_codec_vp8_dx(), NULL, 0) != VPX_CODEC_OK) { + qWarning("Vpx decoder could not be initialised"); + } +} + +QXmppVpxDecoder::~QXmppVpxDecoder() +{ + vpx_codec_destroy(&d->codec); + delete d; +} + +QXmppVideoFormat QXmppVpxDecoder::format() const +{ + QXmppVideoFormat format; + format.setFrameRate(15.0); + format.setFrameSize(QSize(320, 240)); + format.setPixelFormat(QXmppVideoFrame::Format_YUV420P); + return format; +} + +QList QXmppVpxDecoder::handlePacket(const QXmppRtpPacket &packet) +{ + QList frames; + + // vp8 deframing: http://tools.ietf.org/html/draft-westin-payload-vp8-00 + QDataStream stream(packet.payload); + quint8 vpx_header; + stream >> vpx_header; + + const bool have_id = (vpx_header & 0x10) != 0; + const quint8 frag_type = (vpx_header & 0x6) >> 1; + if (have_id) { + qWarning("Vpx decoder does not support pictureId yet"); + return frames; + } + + const int packetLength = packet.payload.size() - 1; +#ifdef QXMPP_DEBUG_VPX + qDebug("Vpx fragment FI: %d, size %d", frag_type, packetLength); +#endif + + QXmppVideoFrame frame; + + if (frag_type == NoFragment) { + // unfragmented packet + if (d->decodeFrame(packet.payload.mid(1), &frame)) + frames << frame; + d->packetBuffer.resize(0); + } else { + // fragments + if (frag_type == StartFragment) { + // start fragment + d->packetBuffer = packet.payload.mid(1); + } else { + // continuation or end fragment + const int packetPos = d->packetBuffer.size(); + d->packetBuffer.resize(packetPos + packetLength); + stream.readRawData(d->packetBuffer.data() + packetPos, packetLength); + } + + if (frag_type == EndFragment) { + // end fragment + if (d->decodeFrame(d->packetBuffer, &frame)) + frames << frame; + d->packetBuffer.resize(0); + } + + } + + return frames; +} + +bool QXmppVpxDecoder::setParameters(const QMap ¶meters) +{ + return true; +} + +class QXmppVpxEncoderPrivate +{ +public: + void writeFragment(QDataStream &stream, FragmentType frag_type, const char *data, quint16 length); + + vpx_codec_ctx_t codec; + vpx_codec_enc_cfg_t cfg; + vpx_image_t *imageBuffer; + int frameCount; +}; + +void QXmppVpxEncoderPrivate::writeFragment(QDataStream &stream, FragmentType frag_type, const char *data, quint16 length) +{ + // vp8 framing: http://tools.ietf.org/html/draft-westin-payload-vp8-00 +#ifdef QXMPP_DEBUG_VPX + qDebug("Vpx encoder writing packet frag: %i, size: %u", frag_type, length); +#endif + stream << quint8(((frag_type << 1) & 0x6) | + (frag_type == NoFragment || frag_type == StartFragment)); + stream.writeRawData(data, length); +} + +QXmppVpxEncoder::QXmppVpxEncoder() +{ + d = new QXmppVpxEncoderPrivate; + d->frameCount = 0; + d->imageBuffer = 0; + vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &d->cfg, 0); +} + +QXmppVpxEncoder::~QXmppVpxEncoder() +{ + vpx_codec_destroy(&d->codec); + if (d->imageBuffer) + vpx_img_free(d->imageBuffer); + delete d; +} + +bool QXmppVpxEncoder::setFormat(const QXmppVideoFormat &format) +{ + const QXmppVideoFrame::PixelFormat pixelFormat = format.pixelFormat(); + if (pixelFormat != QXmppVideoFrame::Format_YUYV) { + qWarning("Vpx encoder does not support the given format"); + return false; + } + + d->cfg.rc_target_bitrate = format.frameSize().width() * format.frameSize().height() * d->cfg.rc_target_bitrate / d->cfg.g_w / d->cfg.g_h; + d->cfg.g_w = format.frameSize().width(); + d->cfg.g_h = format.frameSize().height(); + if (vpx_codec_enc_init(&d->codec, vpx_codec_vp8_cx(), &d->cfg, 0) != VPX_CODEC_OK) { + qWarning("Vpx encoder could not be initialised"); + return false; + } + + d->imageBuffer = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, + format.frameSize().width(), format.frameSize().height(), 1); + return true; +} + +QList QXmppVpxEncoder::handleFrame(const QXmppVideoFrame &frame) +{ + const int PACKET_MAX = 1388; + QList packets; + + // try to encode frame + if (frame.pixelFormat() == QXmppVideoFrame::Format_YUYV) { + // YUYV -> YUV420P + const int width = frame.width(); + const int height = frame.height(); + const int stride = frame.bytesPerLine(); + const uchar *row = frame.bits(); + uchar *y_row = d->imageBuffer->planes[VPX_PLANE_Y]; + uchar *cb_row = d->imageBuffer->planes[VPX_PLANE_U]; + uchar *cr_row = d->imageBuffer->planes[VPX_PLANE_V]; + for (int y = 0; y < height; y += 2) { + // odd row + const uchar *ptr = row; + uchar *y_out = y_row; + uchar *cb_out = cb_row; + uchar *cr_out = cr_row; + for (int x = 0; x < width; x += 2) { + *(y_out++) = *(ptr++); + *(cb_out++) = *(ptr++); + *(y_out++) = *(ptr++); + *(cr_out++) = *(ptr++); + } + row += stride; + y_row += d->imageBuffer->stride[VPX_PLANE_Y]; + cb_row += d->imageBuffer->stride[VPX_PLANE_U]; + cr_row += d->imageBuffer->stride[VPX_PLANE_V]; + + // even row + ptr = row; + y_out = y_row; + for (int x = 0; x < width; x += 2) { + *(y_out++) = *(ptr++); + ptr++; + *(y_out++) = *(ptr++); + ptr++; + } + row += stride; + y_row += d->imageBuffer->stride[VPX_PLANE_Y]; + } + } else { + qWarning("Vpx encoder does not support the given format"); + return packets; + } + + if (vpx_codec_encode(&d->codec, d->imageBuffer, d->frameCount, 1, 0, VPX_DL_REALTIME) != VPX_CODEC_OK) { + qWarning("Vpx encoder could not handle frame: %s", vpx_codec_error_detail(&d->codec)); + return packets; + } + + // extract data + QByteArray payload; + vpx_codec_iter_t iter = NULL; + const vpx_codec_cx_pkt_t *pkt; + while ((pkt = vpx_codec_get_cx_data(&d->codec, &iter))) { + if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { +#ifdef QXMPP_DEBUG_VPX + qDebug("Vpx encoded packet %lu bytes", pkt->data.frame.sz); +#endif + QDataStream stream(&payload, QIODevice::WriteOnly); + const char *data = (const char*) pkt->data.frame.buf; + int size = pkt->data.frame.sz; + if (size <= PACKET_MAX) { + // no fragmentation + stream.device()->reset(); + payload.resize(0); + d->writeFragment(stream, NoFragment, data, size); + packets << payload; + } else { + // fragmentation + FragmentType frag_type = StartFragment; + while (size) { + const int length = qMin(PACKET_MAX, size); + stream.device()->reset(); + payload.resize(0); + d->writeFragment(stream, frag_type, data, length); + data += length; + size -= length; + frag_type = (size > PACKET_MAX) ? MiddleFragment : EndFragment; + packets << payload; + } + } + } + } + d->frameCount++; + + return packets; +} + +QMap QXmppVpxEncoder::parameters() const +{ + return QMap(); +} + +#endif diff --git a/src/base/QXmppCodec.h b/src/base/QXmppCodec.h new file mode 100644 index 00000000..61dd45a2 --- /dev/null +++ b/src/base/QXmppCodec.h @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPCODEC_H +#define QXMPPCODEC_H + +#include + +class QXmppRtpPacket; +class QXmppVideoFormat; +class QXmppVideoFrame; + +/// \brief The QXmppCodec class is the base class for audio codecs capable of +/// encoding and decoding audio samples. +/// +/// Samples must be 16-bit little endian. + +class QXmppCodec +{ +public: + /// Reads samples from the input stream, encodes them and writes the + /// encoded data to the output stream. + virtual qint64 encode(QDataStream &input, QDataStream &output) = 0; + + /// Reads encoded data from the input stream, decodes it and writes the + /// decoded samples to the output stream. + virtual qint64 decode(QDataStream &input, QDataStream &output) = 0; +}; + +/// \internal +/// +/// The QXmppG711aCodec class represent a G.711 a-law PCM codec. + +class QXmppG711aCodec : public QXmppCodec +{ +public: + QXmppG711aCodec(int clockrate); + + qint64 encode(QDataStream &input, QDataStream &output); + qint64 decode(QDataStream &input, QDataStream &output); + +private: + int m_frequency; +}; + +/// \internal +/// +/// The QXmppG711uCodec class represent a G.711 u-law PCM codec. + +class QXmppG711uCodec : public QXmppCodec +{ +public: + QXmppG711uCodec(int clockrate); + + qint64 encode(QDataStream &input, QDataStream &output); + qint64 decode(QDataStream &input, QDataStream &output); + +private: + int m_frequency; +}; + +#ifdef QXMPP_USE_SPEEX +typedef struct SpeexBits SpeexBits; + +/// \internal +/// +/// The QXmppSpeexCodec class represent a SPEEX codec. + +class QXmppSpeexCodec : public QXmppCodec +{ +public: + QXmppSpeexCodec(int clockrate); + ~QXmppSpeexCodec(); + + qint64 encode(QDataStream &input, QDataStream &output); + qint64 decode(QDataStream &input, QDataStream &output); + +private: + SpeexBits *encoder_bits; + void *encoder_state; + SpeexBits *decoder_bits; + void *decoder_state; + int frame_samples; +}; +#endif + +/// \brief The QXmppVideoDecoder class is the base class for video decoders. +/// + +class QXmppVideoDecoder +{ +public: + virtual QXmppVideoFormat format() const = 0; + virtual QList handlePacket(const QXmppRtpPacket &packet) = 0; + virtual bool setParameters(const QMap ¶meters) = 0; +}; + +class QXmppVideoEncoder +{ +public: + virtual bool setFormat(const QXmppVideoFormat &format) = 0; + virtual QList handleFrame(const QXmppVideoFrame &frame) = 0; + virtual QMap parameters() const = 0; +}; + +#ifdef QXMPP_USE_THEORA +class QXmppTheoraDecoderPrivate; +class QXmppTheoraEncoderPrivate; + +class QXmppTheoraDecoder : public QXmppVideoDecoder +{ +public: + QXmppTheoraDecoder(); + ~QXmppTheoraDecoder(); + + QXmppVideoFormat format() const; + QList handlePacket(const QXmppRtpPacket &packet); + bool setParameters(const QMap ¶meters); + +private: + QXmppTheoraDecoderPrivate *d; +}; + +class QXmppTheoraEncoder : public QXmppVideoEncoder +{ +public: + QXmppTheoraEncoder(); + ~QXmppTheoraEncoder(); + + bool setFormat(const QXmppVideoFormat &format); + QList handleFrame(const QXmppVideoFrame &frame); + QMap parameters() const; + +private: + QXmppTheoraEncoderPrivate *d; +}; +#endif + +#ifdef QXMPP_USE_VPX +class QXmppVpxDecoderPrivate; +class QXmppVpxEncoderPrivate; + +class QXmppVpxDecoder : public QXmppVideoDecoder +{ +public: + QXmppVpxDecoder(); + ~QXmppVpxDecoder(); + + QXmppVideoFormat format() const; + QList handlePacket(const QXmppRtpPacket &packet); + bool setParameters(const QMap ¶meters); + +private: + QXmppVpxDecoderPrivate *d; +}; + +class QXmppVpxEncoder : public QXmppVideoEncoder +{ +public: + QXmppVpxEncoder(); + ~QXmppVpxEncoder(); + + bool setFormat(const QXmppVideoFormat &format); + QList handleFrame(const QXmppVideoFrame &frame); + QMap parameters() const; + +private: + QXmppVpxEncoderPrivate *d; +}; +#endif + +#endif diff --git a/src/base/QXmppConstants.cpp b/src/base/QXmppConstants.cpp new file mode 100644 index 00000000..c77859b6 --- /dev/null +++ b/src/base/QXmppConstants.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#include "QXmppConstants.h" + +const char* ns_stream = "http://etherx.jabber.org/streams"; +const char* ns_client = "jabber:client"; +const char* ns_server = "jabber:server"; +const char* ns_server_dialback = "jabber:server:dialback"; +const char* ns_roster = "jabber:iq:roster"; +const char* ns_tls = "urn:ietf:params:xml:ns:xmpp-tls"; +const char* ns_sasl = "urn:ietf:params:xml:ns:xmpp-sasl"; +const char* ns_bind = "urn:ietf:params:xml:ns:xmpp-bind"; +const char* ns_session = "urn:ietf:params:xml:ns:xmpp-session"; +const char* ns_stanza = "urn:ietf:params:xml:ns:xmpp-stanzas"; +const char* ns_vcard = "vcard-temp"; +const char* ns_vcard_update = "vcard-temp:x:update"; +const char* ns_auth = "jabber:iq:auth"; +const char* ns_authFeature = "http://jabber.org/features/iq-auth"; +const char* ns_capabilities = "http://jabber.org/protocol/caps"; +const char* ns_compress = "http://jabber.org/protocol/compress"; +const char* ns_compressFeature = "http://jabber.org/features/compress"; +const char* ns_disco_info = "http://jabber.org/protocol/disco#info"; +const char* ns_disco_items = "http://jabber.org/protocol/disco#items"; +const char* ns_ibb = "http://jabber.org/protocol/ibb"; +const char* ns_rpc = "jabber:iq:rpc"; +const char *ns_ping = "urn:xmpp:ping"; +const char *ns_conference = "jabber:x:conference"; +const char *ns_message_receipts = "urn:xmpp:receipts"; +const char *ns_delayed_delivery = "urn:xmpp:delay"; +const char *ns_legacy_delayed_delivery = "jabber:x:delay"; +const char *ns_muc = "http://jabber.org/protocol/muc"; +const char *ns_muc_admin = "http://jabber.org/protocol/muc#admin"; +const char *ns_muc_owner = "http://jabber.org/protocol/muc#owner"; +const char *ns_muc_user = "http://jabber.org/protocol/muc#user"; +const char *ns_chat_states = "http://jabber.org/protocol/chatstates"; +const char *ns_stream_initiation = "http://jabber.org/protocol/si"; +const char *ns_stream_initiation_file_transfer = "http://jabber.org/protocol/si/profile/file-transfer"; +const char *ns_feature_negotiation = "http://jabber.org/protocol/feature-neg"; +const char *ns_bytestreams = "http://jabber.org/protocol/bytestreams"; +// XEP-0092: Software Version +const char *ns_version = "jabber:iq:version"; +const char *ns_data = "jabber:x:data"; +// XEP-0166: Jingle +const char *ns_jingle = "urn:xmpp:jingle:1"; +const char *ns_jingle_raw_udp = "urn:xmpp:jingle:transports:raw-udp:1"; +const char* ns_jingle_ice_udp = "urn:xmpp:jingle:transports:ice-udp:1"; +const char *ns_jingle_rtp = "urn:xmpp:jingle:apps:rtp:1"; +const char *ns_jingle_rtp_audio = "urn:xmpp:jingle:apps:rtp:audio"; +const char *ns_jingle_rtp_video = "urn:xmpp:jingle:apps:rtp:video"; +// XEP-0202: Entity Time +const char *ns_entity_time = "urn:xmpp:time"; +// XEP-0224: Attention +const char *ns_attention = "urn:xmpp:attention:0"; diff --git a/src/base/QXmppConstants.h b/src/base/QXmppConstants.h new file mode 100644 index 00000000..909bddd9 --- /dev/null +++ b/src/base/QXmppConstants.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPCONSTANTS_H +#define QXMPPCONSTANTS_H + +extern const char* ns_stream; +extern const char* ns_client; +extern const char* ns_server; +extern const char* ns_server_dialback; +extern const char* ns_roster; +extern const char* ns_tls; +extern const char* ns_sasl; +extern const char* ns_bind; +extern const char* ns_session; +extern const char* ns_stanza; +extern const char* ns_vcard; +extern const char* ns_vcard_update; +extern const char* ns_auth; +extern const char* ns_authFeature; +extern const char* ns_capabilities; +extern const char* ns_compress; +extern const char* ns_compressFeature; +extern const char* ns_disco_info; +extern const char* ns_disco_items; +extern const char* ns_ibb; +extern const char* ns_rpc; +extern const char* ns_ping; +extern const char *ns_conference; +extern const char *ns_message_receipts; +extern const char *ns_delayed_delivery; +extern const char *ns_legacy_delayed_delivery; +extern const char *ns_muc; +extern const char *ns_muc_admin; +extern const char *ns_muc_owner; +extern const char *ns_muc_user; +extern const char *ns_chat_states; +extern const char *ns_stream_initiation; +extern const char *ns_stream_initiation_file_transfer; +extern const char *ns_feature_negotiation; +extern const char *ns_bytestreams; +extern const char *ns_version; +extern const char *ns_data; +extern const char *ns_jingle; +extern const char* ns_jingle_ice_udp; +extern const char* ns_jingle_raw_udp; +extern const char *ns_jingle_rtp; +extern const char *ns_jingle_rtp_audio; +extern const char *ns_jingle_rtp_video; +extern const char *ns_entity_time; +extern const char *ns_attention; + +#endif // QXMPPCONSTANTS_H diff --git a/src/base/QXmppDataForm.cpp b/src/base/QXmppDataForm.cpp new file mode 100644 index 00000000..aab3857d --- /dev/null +++ b/src/base/QXmppDataForm.cpp @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include +#include +#include + +#include "QXmppConstants.h" +#include "QXmppDataForm.h" +#include "QXmppUtils.h" + +struct field_type { + QXmppDataForm::Field::Type type; + const char *str; +}; + +static field_type field_types[] = { + {QXmppDataForm::Field::BooleanField, "boolean"}, + {QXmppDataForm::Field::FixedField, "fixed"}, + {QXmppDataForm::Field::HiddenField, "hidden"}, + {QXmppDataForm::Field::JidMultiField, "jid-multi"}, + {QXmppDataForm::Field::JidSingleField, "jid-single"}, + {QXmppDataForm::Field::ListMultiField, "list-multi"}, + {QXmppDataForm::Field::ListSingleField, "list-single"}, + {QXmppDataForm::Field::TextMultiField, "text-multi"}, + {QXmppDataForm::Field::TextPrivateField, "text-private"}, + {QXmppDataForm::Field::TextSingleField, "text-single"}, + {static_cast(-1), NULL}, +}; + +/// Constructs a QXmppDataForm::Field of the specified \a type. +/// +/// \param type + +QXmppDataForm::Field::Field(QXmppDataForm::Field::Type type) + : m_required(false), + m_type(type) +{ +} + +/// Returns the field's description. + +QString QXmppDataForm::Field::description() const +{ + return m_description; +} + +/// Sets the field's description. +/// +/// \param description + +void QXmppDataForm::Field::setDescription(const QString &description) +{ + m_description = description; +} + +/// Returns the field's key. + +QString QXmppDataForm::Field::key() const +{ + return m_key; +} + +/// Sets the field's key. +/// +/// \param key + +void QXmppDataForm::Field::setKey(const QString &key) +{ + m_key = key; +} + +/// Returns the field's label. + +QString QXmppDataForm::Field::label() const +{ + return m_label; +} + +/// Sets the field's label. +/// +/// \param label + +void QXmppDataForm::Field::setLabel(const QString &label) +{ + m_label = label; +} + +/// Returns the field's options. + +QList > QXmppDataForm::Field::options() const +{ + return m_options; +} + +/// Sets the field's options. +/// +/// \param options + +void QXmppDataForm::Field::setOptions(const QList > &options) +{ + m_options = options; +} + +/// Returns true if the field is required, false otherwise. + +bool QXmppDataForm::Field::isRequired() const +{ + return m_required; +} + +/// Set to true if the field is required, false otherwise. +/// +/// \param required + +void QXmppDataForm::Field::setRequired(bool required) +{ + m_required = required; +} + +/// Returns the field's type. + +QXmppDataForm::Field::Type QXmppDataForm::Field::type() const +{ + return m_type; +} + +/// Sets the field's type. +/// +/// \param type + +void QXmppDataForm::Field::setType(QXmppDataForm::Field::Type type) +{ + m_type = type; +} + +/// Returns the field's value. + +QVariant QXmppDataForm::Field::value() const +{ + return m_value; +} + +/// Sets the field's value. +/// +/// \param value + +void QXmppDataForm::Field::setValue(const QVariant &value) +{ + m_value = value; +} + +/// Constructs a QXmppDataForm of the specified \a type. +/// +/// \param type + +QXmppDataForm::QXmppDataForm(QXmppDataForm::Type type) + : m_type(type) +{ +} + +/// Returns the form's fields. + +QList QXmppDataForm::fields() const +{ + return m_fields; +} + +/// Returns the form's fields by reference. + +QList &QXmppDataForm::fields() +{ + return m_fields; +} + +/// Sets the form's fields. +/// +/// \param fields + +void QXmppDataForm::setFields(const QList &fields) +{ + m_fields = fields; +} + +/// Returns the form's instructions. + +QString QXmppDataForm::instructions() const +{ + return m_instructions; +} + +/// Sets the form's instructions. +/// +/// \param instructions + +void QXmppDataForm::setInstructions(const QString &instructions) +{ + m_instructions = instructions; +} + +/// Returns the form's title. + +QString QXmppDataForm::title() const +{ + return m_title; +} + +/// Sets the form's title. +/// +/// \param title + +void QXmppDataForm::setTitle(const QString &title) +{ + m_title = title; +} + +/// Returns the form's type. + +QXmppDataForm::Type QXmppDataForm::type() const +{ + return m_type; +} + +/// Sets the form's type. +/// +/// \param type + +void QXmppDataForm::setType(QXmppDataForm::Type type) +{ + m_type = type; +} + +/// Returns true if the form has an unknown type. + +bool QXmppDataForm::isNull() const +{ + return m_type == QXmppDataForm::None; +} + +void QXmppDataForm::parse(const QDomElement &element) +{ + if (element.isNull()) + return; + + /* form type */ + const QString typeStr = element.attribute("type"); + if (typeStr == "form") + m_type = QXmppDataForm::Form; + else if (typeStr == "submit") + m_type = QXmppDataForm::Submit; + else if (typeStr == "cancel") + m_type = QXmppDataForm::Cancel; + else if (typeStr == "result") + m_type = QXmppDataForm::Result; + else + { + qWarning() << "Unknown form type" << typeStr; + return; + } + + /* form properties */ + m_title = element.firstChildElement("title").text(); + m_instructions = element.firstChildElement("instructions").text(); + + QDomElement fieldElement = element.firstChildElement("field"); + while (!fieldElement.isNull()) + { + QXmppDataForm::Field field; + + /* field type */ + QXmppDataForm::Field::Type type = QXmppDataForm::Field::TextSingleField; + const QString typeStr = fieldElement.attribute("type"); + struct field_type *ptr; + for (ptr = field_types; ptr->str; ptr++) + { + if (typeStr == ptr->str) + { + type = ptr->type; + break; + } + } + field.setType(type); + + /* field attributes */ + field.setLabel(fieldElement.attribute("label")); + field.setKey(fieldElement.attribute("var")); + + /* field value(s) */ + if (type == QXmppDataForm::Field::BooleanField) + { + const QString valueStr = fieldElement.firstChildElement("value").text(); + field.setValue(valueStr == "1" || valueStr == "true"); + } + else if (type == QXmppDataForm::Field::ListMultiField || + type == QXmppDataForm::Field::JidMultiField || + type == QXmppDataForm::Field::TextMultiField) + { + QStringList values; + QDomElement valueElement = fieldElement.firstChildElement("value"); + while (!valueElement.isNull()) + { + values.append(valueElement.text()); + valueElement = valueElement.nextSiblingElement("value"); + } + field.setValue(values); + } + else + { + field.setValue(fieldElement.firstChildElement("value").text()); + } + + /* field options */ + if (type == QXmppDataForm::Field::ListMultiField || + type == QXmppDataForm::Field::ListSingleField) + { + QList > options; + QDomElement optionElement = fieldElement.firstChildElement("option"); + while (!optionElement.isNull()) + { + options.append(QPair(optionElement.attribute("label"), + optionElement.firstChildElement("value").text())); + optionElement = optionElement.nextSiblingElement("option"); + } + field.setOptions(options); + } + + /* other properties */ + field.setDescription(fieldElement.firstChildElement("description").text()); + field.setRequired(!fieldElement.firstChildElement("required").isNull()); + + m_fields.append(field); + + fieldElement = fieldElement.nextSiblingElement("field"); + } +} + +void QXmppDataForm::toXml(QXmlStreamWriter *writer) const +{ + if (isNull()) + return; + + writer->writeStartElement("x"); + writer->writeAttribute("xmlns", ns_data); + + /* form type */ + QString typeStr; + if (m_type == QXmppDataForm::Form) + typeStr = "form"; + else if (m_type == QXmppDataForm::Submit) + typeStr = "submit"; + else if (m_type == QXmppDataForm::Cancel) + typeStr = "cancel"; + else if (m_type == QXmppDataForm::Result) + typeStr = "result"; + helperToXmlAddAttribute(writer, "type", typeStr); + + /* form properties */ + if (!m_title.isEmpty()) + helperToXmlAddTextElement(writer, "title", m_title); + if (!m_instructions.isEmpty()) + helperToXmlAddTextElement(writer, "instructions", m_instructions); + + + foreach (const QXmppDataForm::Field &field, m_fields) + { + writer->writeStartElement("field"); + + /* field type */ + const QXmppDataForm::Field::Type type = field.type(); + QString typeStr; + struct field_type *ptr; + for (ptr = field_types; ptr->str; ptr++) + { + if (type == ptr->type) + { + typeStr = ptr->str; + break; + } + } + helperToXmlAddAttribute(writer, "type", typeStr); + + /* field attributes */ + helperToXmlAddAttribute(writer, "label", field.label()); + helperToXmlAddAttribute(writer, "var", field.key()); + + /* field value(s) */ + if (type == QXmppDataForm::Field::BooleanField) + { + helperToXmlAddTextElement(writer, "value", field.value().toBool() ? "1" : "0"); + } + else if (type == QXmppDataForm::Field::ListMultiField || + type == QXmppDataForm::Field::JidMultiField || + type == QXmppDataForm::Field::TextMultiField) + { + foreach (const QString &value, field.value().toStringList()) + helperToXmlAddTextElement(writer, "value", value); + } + else + { + helperToXmlAddTextElement(writer, "value", field.value().toString()); + } + + /* field options */ + if (type == QXmppDataForm::Field::ListMultiField || + type == QXmppDataForm::Field::ListSingleField) + { + QPair option; + foreach (option, field.options()) + { + writer->writeStartElement("option"); + helperToXmlAddAttribute(writer, "label", option.first); + helperToXmlAddTextElement(writer, "value", option.second); + writer->writeEndElement(); + } + } + + /* other properties */ + if (!field.description().isEmpty()) + helperToXmlAddTextElement(writer, "description", field.description()); + if (field.isRequired()) + helperToXmlAddTextElement(writer, "required", ""); + + writer->writeEndElement(); + } + + writer->writeEndElement(); +} + diff --git a/src/base/QXmppDataForm.h b/src/base/QXmppDataForm.h new file mode 100644 index 00000000..4f38a932 --- /dev/null +++ b/src/base/QXmppDataForm.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPDATAFORM_H +#define QXMPPDATAFORM_H + +#include +#include +#include +#include + +class QDomElement; + +/// \brief The QXmppDataForm class represents a data form as defined by +/// XEP-0004: Data Forms. +/// + +class QXmppDataForm +{ +public: + /// \brief The QXmppDataForm::Field class represents a data form field + /// as defined by XEP-0004: Data Forms. + /// + + class Field + { + public: + /// This enum is used to describe a field's type. + enum Type + { + BooleanField, + FixedField, + HiddenField, + JidMultiField, + JidSingleField, + ListMultiField, + ListSingleField, + TextMultiField, + TextPrivateField, + TextSingleField, + }; + + Field(QXmppDataForm::Field::Type type = QXmppDataForm::Field::TextSingleField); + + QString description() const; + void setDescription(const QString &description); + + QString key() const; + void setKey(const QString &key); + + QString label() const; + void setLabel(const QString &label); + + QList > options() const; + void setOptions(const QList > &options); + + bool isRequired() const; + void setRequired(bool required); + + QXmppDataForm::Field::Type type() const; + void setType(QXmppDataForm::Field::Type type); + + QVariant value() const; + void setValue(const QVariant &value); + + private: + QString m_description; + QString m_key; + QString m_label; + QList > m_options; + bool m_required; + QXmppDataForm::Field::Type m_type; + QVariant m_value; + }; + + /// This enum is used to describe a form's type. + enum Type + { + None, ///< Unknown form type + Form, ///< The form-processing entity is asking the form-submitting + ///< entity to complete a form. + Submit, ///< The form-submitting entity is submitting data to the + ///< form-processing entity. + Cancel, ///< The form-submitting entity has cancelled submission + ///< of data to the form-processing entity. + Result, ///< The form-processing entity is returning data + ///< (e.g., search results) to the form-submitting entity, + ///< or the data is a generic data set. + }; + + QXmppDataForm(QXmppDataForm::Type type = QXmppDataForm::None); + + QString instructions() const; + void setInstructions(const QString &instructions); + + QList fields() const; + QList &fields(); + void setFields(const QList &fields); + + QString title() const; + void setTitle(const QString &title); + + QXmppDataForm::Type type() const; + void setType(QXmppDataForm::Type type); + + bool isNull() const; + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString m_instructions; + QList m_fields; + QString m_title; + QXmppDataForm::Type m_type; +}; + +#endif diff --git a/src/base/QXmppDiscoveryIq.cpp b/src/base/QXmppDiscoveryIq.cpp new file mode 100644 index 00000000..6e0d33d5 --- /dev/null +++ b/src/base/QXmppDiscoveryIq.cpp @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include +#include + +#include "QXmppConstants.h" +#include "QXmppDiscoveryIq.h" +#include "QXmppUtils.h" + +static bool identityLessThan(const QXmppDiscoveryIq::Identity &i1, const QXmppDiscoveryIq::Identity &i2) +{ + if (i1.category() < i2.category()) + return true; + else if (i1.category() > i2.category()) + return false; + + if (i1.type() < i2.type()) + return true; + else if (i1.type() > i2.type()) + return false; + + if (i1.language() < i2.language()) + return true; + else if (i1.language() > i2.language()) + return false; + + if (i1.name() < i2.name()) + return true; + else if (i1.name() > i2.name()) + return false; + + return false; +} + +QString QXmppDiscoveryIq::Identity::category() const +{ + return m_category; +} + +void QXmppDiscoveryIq::Identity::setCategory(const QString &category) +{ + m_category = category; +} + +QString QXmppDiscoveryIq::Identity::language() const +{ + return m_language; +} + +void QXmppDiscoveryIq::Identity::setLanguage(const QString &language) +{ + m_language = language; +} + +QString QXmppDiscoveryIq::Identity::name() const +{ + return m_name; +} + +void QXmppDiscoveryIq::Identity::setName(const QString &name) +{ + m_name = name; +} + +QString QXmppDiscoveryIq::Identity::type() const +{ + return m_type; +} + +void QXmppDiscoveryIq::Identity::setType(const QString &type) +{ + m_type = type; +} + +QString QXmppDiscoveryIq::Item::jid() const +{ + return m_jid; +} + +void QXmppDiscoveryIq::Item::setJid(const QString &jid) +{ + m_jid = jid; +} + +QString QXmppDiscoveryIq::Item::name() const +{ + return m_name; +} + +void QXmppDiscoveryIq::Item::setName(const QString &name) +{ + m_name = name; +} + +QString QXmppDiscoveryIq::Item::node() const +{ + return m_node; +} + +void QXmppDiscoveryIq::Item::setNode(const QString &node) +{ + m_node = node; +} + +QStringList QXmppDiscoveryIq::features() const +{ + return m_features; +} + +void QXmppDiscoveryIq::setFeatures(const QStringList &features) +{ + m_features = features; +} + +QList QXmppDiscoveryIq::identities() const +{ + return m_identities; +} + +void QXmppDiscoveryIq::setIdentities(const QList &identities) +{ + m_identities = identities; +} + +QList QXmppDiscoveryIq::items() const +{ + return m_items; +} + +void QXmppDiscoveryIq::setItems(const QList &items) +{ + m_items = items; +} + +/// Returns the QXmppDataForm for this IQ, as defined by +/// XEP-0128: Service Discovery Extensions. +/// + +QXmppDataForm QXmppDiscoveryIq::form() const +{ + return m_form; +} + +/// Sets the QXmppDataForm for this IQ, as define by +/// XEP-0128: Service Discovery Extensions. +/// +/// \param form +/// + +void QXmppDiscoveryIq::setForm(const QXmppDataForm &form) +{ + m_form = form; +} + +QString QXmppDiscoveryIq::queryNode() const +{ + return m_queryNode; +} + +void QXmppDiscoveryIq::setQueryNode(const QString &node) +{ + m_queryNode = node; +} + +enum QXmppDiscoveryIq::QueryType QXmppDiscoveryIq::queryType() const +{ + return m_queryType; +} + +void QXmppDiscoveryIq::setQueryType(enum QXmppDiscoveryIq::QueryType type) +{ + m_queryType = type; +} + +/// Calculate the verification string for XEP-0115 : Entity Capabilities + +QByteArray QXmppDiscoveryIq::verificationString() const +{ + QString S; + QList sortedIdentities = m_identities; + qSort(sortedIdentities.begin(), sortedIdentities.end(), identityLessThan); + QStringList sortedFeatures = m_features; + qSort(sortedFeatures); + foreach (const QXmppDiscoveryIq::Identity &identity, sortedIdentities) + S += QString("%1/%2/%3/%4<").arg(identity.category(), identity.type(), identity.language(), identity.name()); + foreach (const QString &feature, sortedFeatures) + S += feature + QLatin1String("<"); + QCryptographicHash hasher(QCryptographicHash::Sha1); + hasher.addData(S.toUtf8()); + return hasher.result(); +} + +bool QXmppDiscoveryIq::isDiscoveryIq(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + return (queryElement.namespaceURI() == ns_disco_info || + queryElement.namespaceURI() == ns_disco_items); +} + +void QXmppDiscoveryIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + m_queryNode = queryElement.attribute("node"); + if (queryElement.namespaceURI() == ns_disco_items) + m_queryType = ItemsQuery; + else + m_queryType = InfoQuery; + + QDomElement itemElement = queryElement.firstChildElement(); + while (!itemElement.isNull()) + { + if (itemElement.tagName() == "feature") + { + m_features.append(itemElement.attribute("var")); + } + else if (itemElement.tagName() == "identity") + { + QXmppDiscoveryIq::Identity identity; + identity.setLanguage(itemElement.attribute("xml:lang")); + identity.setCategory(itemElement.attribute("category")); + identity.setName(itemElement.attribute("name")); + identity.setType(itemElement.attribute("type")); + m_identities.append(identity); + } + else if (itemElement.tagName() == "item") + { + QXmppDiscoveryIq::Item item; + item.setJid(itemElement.attribute("jid")); + item.setName(itemElement.attribute("name")); + item.setNode(itemElement.attribute("node")); + m_items.append(item); + } + else if (itemElement.tagName() == "x" && + itemElement.namespaceURI() == ns_data) + { + m_form.parse(itemElement); + } + itemElement = itemElement.nextSiblingElement(); + } +} + +void QXmppDiscoveryIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("query"); + writer->writeAttribute("xmlns", + m_queryType == InfoQuery ? ns_disco_info : ns_disco_items); + helperToXmlAddAttribute(writer, "node", m_queryNode); + + foreach (const QString &feature, m_features) + { + writer->writeStartElement("feature"); + helperToXmlAddAttribute(writer, "var", feature); + writer->writeEndElement(); + } + + foreach (const QXmppDiscoveryIq::Identity& identity, m_identities) + { + writer->writeStartElement("identity"); + helperToXmlAddAttribute(writer, "xml:lang", identity.language()); + helperToXmlAddAttribute(writer, "category", identity.category()); + helperToXmlAddAttribute(writer, "name", identity.name()); + helperToXmlAddAttribute(writer, "type", identity.type()); + writer->writeEndElement(); + } + + foreach (const QXmppDiscoveryIq::Item& item, m_items) + { + writer->writeStartElement("item"); + helperToXmlAddAttribute(writer, "jid", item.jid()); + helperToXmlAddAttribute(writer, "name", item.name()); + helperToXmlAddAttribute(writer, "node", item.node()); + writer->writeEndElement(); + } + + m_form.toXml(writer); + + writer->writeEndElement(); +} + diff --git a/src/base/QXmppDiscoveryIq.h b/src/base/QXmppDiscoveryIq.h new file mode 100644 index 00000000..40aa1a3b --- /dev/null +++ b/src/base/QXmppDiscoveryIq.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPDISCOVERY_H +#define QXMPPDISCOVERY_H + +#include "QXmppDataForm.h" +#include "QXmppIq.h" + +class QDomElement; + +class QXmppDiscoveryIq : public QXmppIq +{ +public: + class Identity + { + public: + QString category() const; + void setCategory(const QString &category); + + QString language() const; + void setLanguage(const QString &language); + + QString name() const; + void setName(const QString &name); + + QString type() const; + void setType(const QString &type); + + private: + QString m_category; + QString m_language; + QString m_name; + QString m_type; + }; + + class Item + { + public: + QString jid() const; + void setJid(const QString &jid); + + QString name() const; + void setName(const QString &name); + + QString node() const; + void setNode(const QString &node); + + private: + QString m_jid; + QString m_name; + QString m_node; + }; + + enum QueryType { + InfoQuery, + ItemsQuery, + }; + + QStringList features() const; + void setFeatures(const QStringList &features); + + QList identities() const; + void setIdentities(const QList &identities); + + QList items() const; + void setItems(const QList &items); + + QXmppDataForm form() const; + void setForm(const QXmppDataForm &form); + + QString queryNode() const; + void setQueryNode(const QString &node); + + enum QueryType queryType() const; + void setQueryType(enum QueryType type); + + QByteArray verificationString() const; + + static bool isDiscoveryIq(const QDomElement &element); + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QStringList m_features; + QList m_identities; + QList m_items; + QXmppDataForm m_form; + QString m_queryNode; + enum QueryType m_queryType; +}; + +#endif diff --git a/src/base/QXmppElement.cpp b/src/base/QXmppElement.cpp new file mode 100644 index 00000000..904ab473 --- /dev/null +++ b/src/base/QXmppElement.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include "QXmppElement.h" +#include "QXmppUtils.h" + +#include + +class QXmppElementPrivate +{ +public: + QXmppElementPrivate(); + QXmppElementPrivate(const QDomElement &element); + ~QXmppElementPrivate(); + + QAtomicInt counter; + + QXmppElementPrivate *parent; + QMap attributes; + QList children; + QString name; + QString value; +}; + +QXmppElementPrivate::QXmppElementPrivate() + : counter(1), parent(NULL) +{ +} + +QXmppElementPrivate::QXmppElementPrivate(const QDomElement &element) + : counter(1), parent(NULL) +{ + if (element.isNull()) + return; + + name = element.tagName(); + QString xmlns = element.namespaceURI(); + QString parentns = element.parentNode().namespaceURI(); + if (!xmlns.isEmpty() && xmlns != parentns) + attributes.insert("xmlns", xmlns); + QDomNamedNodeMap attrs = element.attributes(); + for (int i = 0; i < attrs.size(); i++) + { + QDomAttr attr = attrs.item(i).toAttr(); + attributes.insert(attr.name(), attr.value()); + } + + QDomNode childNode = element.firstChild(); + while (!childNode.isNull()) + { + if (childNode.isElement()) + { + QXmppElementPrivate *child = new QXmppElementPrivate(childNode.toElement()); + child->parent = this; + children.append(child); + } else if (childNode.isText()) { + value += childNode.toText().data(); + } + childNode = childNode.nextSibling(); + } +} + +QXmppElementPrivate::~QXmppElementPrivate() +{ + foreach (QXmppElementPrivate *child, children) + if (!child->counter.deref()) + delete child; +} + +QXmppElement::QXmppElement() +{ + d = new QXmppElementPrivate(); +} + +QXmppElement::QXmppElement(const QXmppElement &other) +{ + other.d->counter.ref(); + d = other.d; +} + +QXmppElement::QXmppElement(QXmppElementPrivate *other) +{ + other->counter.ref(); + d = other; +} + +QXmppElement::QXmppElement(const QDomElement &element) +{ + d = new QXmppElementPrivate(element); +} + +QXmppElement::~QXmppElement() +{ + if (!d->counter.deref()) + delete d; +} + +QXmppElement &QXmppElement::operator=(const QXmppElement &other) +{ + other.d->counter.ref(); + if (!d->counter.deref()) + delete d; + d = other.d; + return *this; +} + +QStringList QXmppElement::attributeNames() const +{ + return d->attributes.keys(); +} + +QString QXmppElement::attribute(const QString &name) const +{ + return d->attributes.value(name); +} + +void QXmppElement::setAttribute(const QString &name, const QString &value) +{ + d->attributes.insert(name, value); +} + +void QXmppElement::appendChild(const QXmppElement &child) +{ + if (child.d->parent == d) + return; + + if (child.d->parent) + child.d->parent->children.removeAll(child.d); + else + child.d->counter.ref(); + child.d->parent = d; + d->children.append(child.d); +} + +QXmppElement QXmppElement::firstChildElement(const QString &name) const +{ + foreach (QXmppElementPrivate *child_d, d->children) + if (name.isEmpty() || child_d->name == name) + return QXmppElement(child_d); + return QXmppElement(); +} + +QXmppElement QXmppElement::nextSiblingElement(const QString &name) const +{ + if (!d->parent) + return QXmppElement(); + const QList &siblings_d = d->parent->children; + for (int i = siblings_d.indexOf(d) + 1; i < siblings_d.size(); i++) + if (name.isEmpty() || siblings_d[i]->name == name) + return QXmppElement(siblings_d[i]); + return QXmppElement(); +} + +bool QXmppElement::isNull() const +{ + return d->name.isEmpty(); +} + +void QXmppElement::removeChild(const QXmppElement &child) +{ + if (child.d->parent != d) + return; + + d->children.removeAll(child.d); + child.d->counter.deref(); + child.d->parent = NULL; +} + +QString QXmppElement::tagName() const +{ + return d->name; +} + +void QXmppElement::setTagName(const QString &tagName) +{ + d->name = tagName; +} + +QString QXmppElement::value() const +{ + return d->value; +} + +void QXmppElement::setValue(const QString &value) +{ + d->value = value; +} + +void QXmppElement::toXml(QXmlStreamWriter *writer) const +{ + if (isNull()) + return; + + writer->writeStartElement(d->name); + if (d->attributes.contains("xmlns")) + writer->writeAttribute("xmlns", d->attributes.value("xmlns")); + foreach (const QString &attr, d->attributes.keys()) + if (attr != "xmlns") + helperToXmlAddAttribute(writer, attr, d->attributes.value(attr)); + if (!d->value.isEmpty()) + writer->writeCharacters(d->value); + foreach (const QXmppElement &child, d->children) + child.toXml(writer); + writer->writeEndElement(); +} + +QXmppElementList::QXmppElementList() +{ +} + +QXmppElementList::QXmppElementList(const QXmppElement &element) +{ + append(element); +} + + +QXmppElementList::QXmppElementList(const QList &other) + : QList(other) +{ +} + diff --git a/src/base/QXmppElement.h b/src/base/QXmppElement.h new file mode 100644 index 00000000..7fa75494 --- /dev/null +++ b/src/base/QXmppElement.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPELEMENT_H +#define QXMPPELEMENT_H + +#include +#include +#include + +class QDomElement; +class QXmppElement; +class QXmppElementPrivate; + +class QXmppElementList : public QList +{ +public: + QXmppElementList(); + QXmppElementList(const QXmppElement &element); + QXmppElementList(const QList &other); +}; + +class QXmppElement +{ +public: + QXmppElement(); + QXmppElement(const QXmppElement &other); + QXmppElement(const QDomElement &element); + ~QXmppElement(); + + QStringList attributeNames() const; + + QString attribute(const QString &name) const; + void setAttribute(const QString &name, const QString &value); + + void appendChild(const QXmppElement &child); + QXmppElement firstChildElement(const QString &name = QString()) const; + QXmppElement nextSiblingElement(const QString &name = QString()) const; + void removeChild(const QXmppElement &child); + + QString tagName() const; + void setTagName(const QString &type); + + QString value() const; + void setValue(const QString &text); + + bool isNull() const; + void toXml(QXmlStreamWriter *writer) const; + + QXmppElement &operator=(const QXmppElement &other); + +private: + QXmppElement(QXmppElementPrivate *other); + QXmppElementPrivate *d; +}; + +#endif diff --git a/src/base/QXmppEntityTimeIq.cpp b/src/base/QXmppEntityTimeIq.cpp new file mode 100644 index 00000000..5e41e39f --- /dev/null +++ b/src/base/QXmppEntityTimeIq.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#include "QXmppEntityTimeIq.h" + +#include + +#include "QXmppConstants.h" +#include "QXmppUtils.h" + +/// Returns the timezone offset in seconds. +/// + +int QXmppEntityTimeIq::tzo() const +{ + return m_tzo; +} + +/// Sets the timezone offset in seconds. +/// +/// \param tzo + +void QXmppEntityTimeIq::setTzo(int tzo) +{ + m_tzo = tzo; +} + +/// Returns the date/time in Coordinated Universal Time (UTC). +/// + +QDateTime QXmppEntityTimeIq::utc() const +{ + return m_utc; +} + +/// Sets the date/time in Coordinated Universal Time (UTC). +/// +/// \param utc + +void QXmppEntityTimeIq::setUtc(const QDateTime &utc) +{ + m_utc = utc; +} + +bool QXmppEntityTimeIq::isEntityTimeIq(const QDomElement &element) +{ + QDomElement timeElement = element.firstChildElement("time"); + return timeElement.namespaceURI() == ns_entity_time; +} + +void QXmppEntityTimeIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement timeElement = element.firstChildElement("time"); + m_tzo = timezoneOffsetFromString(timeElement.firstChildElement("tzo").text()); + m_utc = datetimeFromString(timeElement.firstChildElement("utc").text()); +} + +void QXmppEntityTimeIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("time"); + writer->writeAttribute("xmlns", ns_entity_time); + + if(m_utc.isValid()) + { + helperToXmlAddTextElement(writer, "tzo", timezoneOffsetToString(m_tzo)); + helperToXmlAddTextElement(writer, "utc", datetimeToString(m_utc)); + } + writer->writeEndElement(); +} diff --git a/src/base/QXmppEntityTimeIq.h b/src/base/QXmppEntityTimeIq.h new file mode 100644 index 00000000..fa3d5f12 --- /dev/null +++ b/src/base/QXmppEntityTimeIq.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPENTITYTIMEIQ_H +#define QXMPPENTITYTIMEIQ_H + +#include + +#include "QXmppIq.h" + +/// \ingroup Stanzas + +class QXmppEntityTimeIq : public QXmppIq +{ +public: + int tzo() const; + void setTzo(int tzo); + + QDateTime utc() const; + void setUtc(const QDateTime &utc); + + static bool isEntityTimeIq(const QDomElement &element); + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + int m_tzo; + QDateTime m_utc; +}; + +#endif //QXMPPENTITYTIMEIQ_H diff --git a/src/base/QXmppGlobal.cpp b/src/base/QXmppGlobal.cpp new file mode 100644 index 00000000..2735788a --- /dev/null +++ b/src/base/QXmppGlobal.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#include "QXmppGlobal.h" + +QString QXmppVersion() +{ + return QString("%1.%2.%3").arg( + QString::number((QXMPP_VERSION >> 16) & 0xff), + QString::number((QXMPP_VERSION >> 8) & 0xff), + QString::number(QXMPP_VERSION & 0xff)); +} + diff --git a/src/base/QXmppGlobal.h b/src/base/QXmppGlobal.h new file mode 100644 index 00000000..36122d1a --- /dev/null +++ b/src/base/QXmppGlobal.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPGLOBAL_H +#define QXMPPGLOBAL_H + +#include + +/// This macro expands a numeric value of the form 0xMMNNPP (MM = +/// major, NN = minor, PP = patch) that specifies QXmpp's version +/// number. For example, if you compile your application against +/// QXmpp 1.2.3, the QXMPP_VERSION macro will expand to 0x010203. +/// +/// You can use QXMPP_VERSION to use the latest QXmpp features where +/// available. +/// + +#define QXMPP_VERSION 0x00035b + +QString QXmppVersion(); + +#endif //QXMPPGLOBAL_H diff --git a/src/base/QXmppIbbIq.cpp b/src/base/QXmppIbbIq.cpp new file mode 100644 index 00000000..85aba54a --- /dev/null +++ b/src/base/QXmppIbbIq.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include +#include + +#include "QXmppConstants.h" +#include "QXmppIbbIq.h" + +QXmppIbbOpenIq::QXmppIbbOpenIq() : QXmppIq(QXmppIq::Set), m_block_size(1024) +{ + +} + +long QXmppIbbOpenIq::blockSize() const +{ + return m_block_size; +} + +void QXmppIbbOpenIq::setBlockSize( long block_size ) +{ + m_block_size = block_size; +} + +QString QXmppIbbOpenIq::sid() const +{ + return m_sid; +} + +void QXmppIbbOpenIq::setSid( const QString &sid ) +{ + m_sid = sid; +} + +bool QXmppIbbOpenIq::isIbbOpenIq(const QDomElement &element) +{ + QDomElement openElement = element.firstChildElement("open"); + return openElement.namespaceURI() == ns_ibb; +} + +void QXmppIbbOpenIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement openElement = element.firstChildElement("open"); + m_sid = openElement.attribute( "sid" ); + m_block_size = openElement.attribute( "block-size" ).toLong(); +} + +void QXmppIbbOpenIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("open"); + writer->writeAttribute( "xmlns",ns_ibb); + writer->writeAttribute( "sid",m_sid); + writer->writeAttribute( "block-size",QString::number(m_block_size) ); + writer->writeEndElement(); +} + +QXmppIbbCloseIq::QXmppIbbCloseIq() : QXmppIq(QXmppIq::Set) +{ + +} + +QString QXmppIbbCloseIq::sid() const +{ + return m_sid; +} + +void QXmppIbbCloseIq::setSid( const QString &sid ) +{ + m_sid = sid; +} + +bool QXmppIbbCloseIq::isIbbCloseIq(const QDomElement &element) +{ + QDomElement openElement = element.firstChildElement("close"); + return openElement.namespaceURI() == ns_ibb; +} + +void QXmppIbbCloseIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement openElement = element.firstChildElement("close"); + m_sid = openElement.attribute( "sid" ); +} + +void QXmppIbbCloseIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("close"); + writer->writeAttribute( "xmlns",ns_ibb); + writer->writeAttribute( "sid",m_sid); + writer->writeEndElement(); +} + +QXmppIbbDataIq::QXmppIbbDataIq() : QXmppIq( QXmppIq::Set ), m_seq(0) +{ +} + +quint16 QXmppIbbDataIq::sequence() const +{ + return m_seq; +} + +void QXmppIbbDataIq::setSequence( quint16 seq ) +{ + m_seq = seq; +} + +QString QXmppIbbDataIq::sid() const +{ + return m_sid; +} + +void QXmppIbbDataIq::setSid( const QString &sid ) +{ + m_sid = sid; +} + +QByteArray QXmppIbbDataIq::payload() const +{ + return m_payload; +} + +void QXmppIbbDataIq::setPayload( const QByteArray &data ) +{ + m_payload = data; +} + +bool QXmppIbbDataIq::isIbbDataIq(const QDomElement &element) +{ + QDomElement dataElement = element.firstChildElement("data"); + return dataElement.namespaceURI() == ns_ibb; +} + +void QXmppIbbDataIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement dataElement = element.firstChildElement("data"); + m_sid = dataElement.attribute( "sid" ); + m_seq = dataElement.attribute( "seq" ).toLong(); + m_payload = QByteArray::fromBase64( dataElement.text().toLatin1() ); +} + +void QXmppIbbDataIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("data"); + writer->writeAttribute( "xmlns",ns_ibb); + writer->writeAttribute( "sid",m_sid); + writer->writeAttribute( "seq",QString::number(m_seq) ); + writer->writeCharacters( m_payload.toBase64() ); + writer->writeEndElement(); +} diff --git a/src/base/QXmppIbbIq.h b/src/base/QXmppIbbIq.h new file mode 100644 index 00000000..592b12f4 --- /dev/null +++ b/src/base/QXmppIbbIq.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPIBBIQ_H +#define QXMPPIBBIQ_H + +#include "QXmppIq.h" + +class QDomElement; +class QXmlStreamWriter; + +class QXmppIbbOpenIq: public QXmppIq +{ +public: + QXmppIbbOpenIq(); + + long blockSize() const; + void setBlockSize( long block_size ); + + QString sid() const; + void setSid( const QString &sid ); + + static bool isIbbOpenIq(const QDomElement &element); + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + long m_block_size; + QString m_sid; +}; + +class QXmppIbbCloseIq: public QXmppIq +{ +public: + QXmppIbbCloseIq(); + + QString sid() const; + void setSid( const QString &sid ); + + static bool isIbbCloseIq(const QDomElement &element); + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString m_sid; +}; + +class QXmppIbbDataIq : public QXmppIq +{ +public: + QXmppIbbDataIq(); + + quint16 sequence() const; + void setSequence( quint16 seq ); + + QString sid() const; + void setSid( const QString &sid ); + + QByteArray payload() const; + void setPayload( const QByteArray &data ); + + static bool isIbbDataIq(const QDomElement &element); + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + quint16 m_seq; + QString m_sid; + QByteArray m_payload; +}; + +#endif // QXMPPIBBIQS_H diff --git a/src/base/QXmppIq.cpp b/src/base/QXmppIq.cpp new file mode 100644 index 00000000..d0ee0a7a --- /dev/null +++ b/src/base/QXmppIq.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#include "QXmppUtils.h" +#include "QXmppIq.h" + +#include +#include + +/// Constructs a QXmppIq with the specified \a type. +/// +/// \param type + +QXmppIq::QXmppIq(QXmppIq::Type type) + : QXmppStanza(), m_type(type) +{ + generateAndSetNextId(); +} + +/// Returns the IQ's type. +/// + +QXmppIq::Type QXmppIq::type() const +{ + return m_type; +} + +/// Sets the IQ's type. +/// +/// \param type + +void QXmppIq::setType(QXmppIq::Type type) +{ + m_type = type; +} + +void QXmppIq::parse(const QDomElement &element) +{ + QXmppStanza::parse(element); + setTypeFromStr(element.attribute("type")); + parseElementFromChild(element); +} + +void QXmppIq::parseElementFromChild(const QDomElement &element) +{ + QXmppElementList extensions; + QDomElement itemElement = element.firstChildElement(); + while (!itemElement.isNull()) + { + extensions.append(QXmppElement(itemElement)); + itemElement = itemElement.nextSiblingElement(); + } + setExtensions(extensions); +} + +void QXmppIq::toXml( QXmlStreamWriter *xmlWriter ) const +{ + xmlWriter->writeStartElement("iq"); + + helperToXmlAddAttribute(xmlWriter, "id", id()); + helperToXmlAddAttribute(xmlWriter, "to", to()); + helperToXmlAddAttribute(xmlWriter, "from", from()); + if(getTypeStr().isEmpty()) + helperToXmlAddAttribute(xmlWriter, "type", "get"); + else + helperToXmlAddAttribute(xmlWriter, "type", getTypeStr()); + toXmlElementFromChild(xmlWriter); + error().toXml(xmlWriter); + xmlWriter->writeEndElement(); +} + +void QXmppIq::toXmlElementFromChild( QXmlStreamWriter *writer ) const +{ + foreach (const QXmppElement &extension, extensions()) + extension.toXml(writer); +} + +QString QXmppIq::getTypeStr() const +{ + switch(m_type) + { + case QXmppIq::Error: + return "error"; + case QXmppIq::Get: + return "get"; + case QXmppIq::Set: + return "set"; + case QXmppIq::Result: + return "result"; + default: + qWarning("QXmppIq::getTypeStr() invalid type %d", (int)m_type); + return ""; + } +} + +void QXmppIq::setTypeFromStr(const QString& str) +{ + if(str == "error") + { + setType(QXmppIq::Error); + return; + } + else if(str == "get") + { + setType(QXmppIq::Get); + return; + } + else if(str == "set") + { + setType(QXmppIq::Set); + return; + } + else if(str == "result") + { + setType(QXmppIq::Result); + return; + } + else + { + setType(static_cast(-1)); + qWarning("QXmppIq::setTypeFromStr() invalid input string type: %s", + qPrintable(str)); + return; + } +} + diff --git a/src/base/QXmppIq.h b/src/base/QXmppIq.h new file mode 100644 index 00000000..bbde3d06 --- /dev/null +++ b/src/base/QXmppIq.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPIQ_H +#define QXMPPIQ_H + +#include "QXmppStanza.h" + +// forward declarations of QXmlStream* classes will not work on Mac, we need to +// include the whole header. +// See http://lists.trolltech.com/qt-interest/2008-07/thread00798-0.html +// for an explanation. +#include + +/// \brief The QXmppIq class is the base class for all IQs. +/// +/// \ingroup Stanzas + +class QXmppIq : public QXmppStanza +{ +public: + /// This enum describes the type of IQ. + enum Type + { + Error = 0, ///< Error response. + Get, ///< Get request. + Set, ///< Set request. + Result ///< Result. + }; + + QXmppIq(QXmppIq::Type type = QXmppIq::Get); + + QXmppIq::Type type() const; + void setType(QXmppIq::Type); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + +protected: + virtual void parseElementFromChild(const QDomElement &element); + virtual void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString getTypeStr() const; + void setTypeFromStr(const QString& str); + + Type m_type; +}; + +#endif // QXMPPIQ_H diff --git a/src/base/QXmppJingleIq.cpp b/src/base/QXmppJingleIq.cpp new file mode 100644 index 00000000..5eb11322 --- /dev/null +++ b/src/base/QXmppJingleIq.cpp @@ -0,0 +1,848 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include "QXmppConstants.h" +#include "QXmppJingleIq.h" +#include "QXmppUtils.h" + +static const char* ns_jingle_rtp_info = "urn:xmpp:jingle:apps:rtp:info:1"; + +static const char* jingle_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* jingle_reasons[] = { + "", + "alternative-session", + "busy", + "cancel", + "connectivity-error", + "decline", + "expired", + "failed-application", + "failed-transport", + "general-error", + "gone", + "incompatible-parameters", + "media-error", + "security-error", + "success", + "timeout", + "unsupported-applications", + "unsupported-transports", +}; + +QXmppJingleIq::Content::Content() +{ +} + +QString QXmppJingleIq::Content::creator() const +{ + return m_creator; +} + +void QXmppJingleIq::Content::setCreator(const QString &creator) +{ + m_creator = creator; +} + +QString QXmppJingleIq::Content::name() const +{ + return m_name; +} + +void QXmppJingleIq::Content::setName(const QString &name) +{ + m_name = name; +} + +QString QXmppJingleIq::Content::senders() const +{ + return m_senders; +} + +void QXmppJingleIq::Content::setSenders(const QString &senders) +{ + m_senders = senders; +} + +QString QXmppJingleIq::Content::descriptionMedia() const +{ + return m_descriptionMedia; +} + +void QXmppJingleIq::Content::setDescriptionMedia(const QString &media) +{ + m_descriptionMedia = media; +} + +void QXmppJingleIq::Content::addPayloadType(const QXmppJinglePayloadType &payload) +{ + m_descriptionType = ns_jingle_rtp; + m_payloadTypes << payload; +} + +QList QXmppJingleIq::Content::payloadTypes() const +{ + return m_payloadTypes; +} + +void QXmppJingleIq::Content::setPayloadTypes(const QList &payloadTypes) +{ + m_descriptionType = payloadTypes.isEmpty() ? QString() : ns_jingle_rtp; + m_payloadTypes = payloadTypes; +} + +void QXmppJingleIq::Content::addTransportCandidate(const QXmppJingleCandidate &candidate) +{ + m_transportType = ns_jingle_ice_udp; + m_transportCandidates << candidate; +} + +QList QXmppJingleIq::Content::transportCandidates() const +{ + return m_transportCandidates; +} + +QString QXmppJingleIq::Content::transportUser() const +{ + return m_transportUser; +} + +void QXmppJingleIq::Content::setTransportUser(const QString &user) +{ + m_transportUser = user; +} + +QString QXmppJingleIq::Content::transportPassword() const +{ + return m_transportPassword; +} + +void QXmppJingleIq::Content::setTransportPassword(const QString &password) +{ + m_transportPassword = password; +} + +void QXmppJingleIq::Content::parse(const QDomElement &element) +{ + m_creator = element.attribute("creator"); + m_disposition = element.attribute("disposition"); + m_name = element.attribute("name"); + m_senders = element.attribute("senders"); + + // description + QDomElement descriptionElement = element.firstChildElement("description"); + m_descriptionType = descriptionElement.namespaceURI(); + m_descriptionMedia = descriptionElement.attribute("media"); + QDomElement child = descriptionElement.firstChildElement("payload-type"); + while (!child.isNull()) + { + QXmppJinglePayloadType payload; + payload.parse(child); + m_payloadTypes << payload; + child = child.nextSiblingElement("payload-type"); + } + + // transport + QDomElement transportElement = element.firstChildElement("transport"); + m_transportType = transportElement.namespaceURI(); + m_transportUser = transportElement.attribute("ufrag"); + m_transportPassword = transportElement.attribute("pwd"); + child = transportElement.firstChildElement("candidate"); + while (!child.isNull()) + { + QXmppJingleCandidate candidate; + candidate.parse(child); + m_transportCandidates << candidate; + child = child.nextSiblingElement("candidate"); + } +} + +void QXmppJingleIq::Content::toXml(QXmlStreamWriter *writer) const +{ + if (m_creator.isEmpty() || m_name.isEmpty()) + return; + + writer->writeStartElement("content"); + helperToXmlAddAttribute(writer, "creator", m_creator); + helperToXmlAddAttribute(writer, "disposition", m_disposition); + helperToXmlAddAttribute(writer, "name", m_name); + helperToXmlAddAttribute(writer, "senders", m_senders); + + // description + if (!m_descriptionType.isEmpty() || !m_payloadTypes.isEmpty()) + { + writer->writeStartElement("description"); + writer->writeAttribute("xmlns", m_descriptionType); + helperToXmlAddAttribute(writer, "media", m_descriptionMedia); + foreach (const QXmppJinglePayloadType &payload, m_payloadTypes) + payload.toXml(writer); + writer->writeEndElement(); + } + + // transport + if (!m_transportType.isEmpty() || !m_transportCandidates.isEmpty()) + { + writer->writeStartElement("transport"); + writer->writeAttribute("xmlns", m_transportType); + helperToXmlAddAttribute(writer, "ufrag", m_transportUser); + helperToXmlAddAttribute(writer, "pwd", m_transportPassword); + foreach (const QXmppJingleCandidate &candidate, m_transportCandidates) + candidate.toXml(writer); + writer->writeEndElement(); + } + writer->writeEndElement(); +} + +QXmppJingleIq::Reason::Reason() + : m_type(None) +{ +} + +QString QXmppJingleIq::Reason::text() const +{ + return m_text; +} + +void QXmppJingleIq::Reason::setText(const QString &text) +{ + m_text = text; +} + +QXmppJingleIq::Reason::Type QXmppJingleIq::Reason::type() const +{ + return m_type; +} + +void QXmppJingleIq::Reason::setType(QXmppJingleIq::Reason::Type type) +{ + m_type = type; +} + +void QXmppJingleIq::Reason::parse(const QDomElement &element) +{ + m_text = element.firstChildElement("text").text(); + for (int i = AlternativeSession; i <= UnsupportedTransports; i++) + { + if (!element.firstChildElement(jingle_reasons[i]).isNull()) + { + m_type = static_cast(i); + break; + } + } +} + +void QXmppJingleIq::Reason::toXml(QXmlStreamWriter *writer) const +{ + if (m_type < AlternativeSession || m_type > UnsupportedTransports) + return; + + writer->writeStartElement("reason"); + if (!m_text.isEmpty()) + helperToXmlAddTextElement(writer, "text", m_text); + writer->writeEmptyElement(jingle_reasons[m_type]); + writer->writeEndElement(); +} + +/// Constructs a QXmppJingleIq. + +QXmppJingleIq::QXmppJingleIq() + : m_ringing(false) +{ +} + +/// Returns the Jingle IQ's action. + +QXmppJingleIq::Action QXmppJingleIq::action() const +{ + return m_action; +} + +/// Sets the Jingle IQ's action. +/// +/// \param action + +void QXmppJingleIq::setAction(QXmppJingleIq::Action action) +{ + m_action = action; +} + +/// Returns the session initiator. + +QString QXmppJingleIq::initiator() const +{ + return m_initiator; +} + +/// Sets the session initiator. +/// +/// \param initiator + +void QXmppJingleIq::setInitiator(const QString &initiator) +{ + m_initiator = initiator; +} + +/// Returns the session responder. + +QString QXmppJingleIq::responder() const +{ + return m_responder; +} + +/// Sets the session responder. +/// +/// \param responder + +void QXmppJingleIq::setResponder(const QString &responder) +{ + m_responder = responder; +} + +/// Returns the session ID. + +QString QXmppJingleIq::sid() const +{ + return m_sid; +} + +/// Sets the session ID. +/// +/// \param sid + +void QXmppJingleIq::setSid(const QString &sid) +{ + m_sid = sid; +} + +bool QXmppJingleIq::isJingleIq(const QDomElement &element) +{ + QDomElement jingleElement = element.firstChildElement("jingle"); + return (jingleElement.namespaceURI() == ns_jingle); +} + +/// Returns true if the call is ringing. + +bool QXmppJingleIq::ringing() const +{ + return m_ringing; +} + +/// Set to true if the call is ringing. +/// +/// \param ringing + +void QXmppJingleIq::setRinging(bool ringing) +{ + m_ringing = ringing; +} + +void QXmppJingleIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement jingleElement = element.firstChildElement("jingle"); + const QString action = jingleElement.attribute("action"); + for (int i = ContentAccept; i <= TransportReplace; i++) + { + if (action == jingle_actions[i]) + { + m_action = static_cast(i); + break; + } + } + m_initiator = jingleElement.attribute("initiator"); + m_responder = jingleElement.attribute("responder"); + m_sid = jingleElement.attribute("sid"); + + // content + QDomElement contentElement = jingleElement.firstChildElement("content"); + m_content.parse(contentElement); + QDomElement reasonElement = jingleElement.firstChildElement("reason"); + m_reason.parse(reasonElement); + + // ringing + QDomElement ringingElement = jingleElement.firstChildElement("ringing"); + m_ringing = (ringingElement.namespaceURI() == ns_jingle_rtp_info); +} + +void QXmppJingleIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("jingle"); + writer->writeAttribute("xmlns", ns_jingle); + helperToXmlAddAttribute(writer, "action", jingle_actions[m_action]); + helperToXmlAddAttribute(writer, "initiator", m_initiator); + helperToXmlAddAttribute(writer, "responder", m_responder); + helperToXmlAddAttribute(writer, "sid", m_sid); + m_content.toXml(writer); + m_reason.toXml(writer); + + // ringing + if (m_ringing) + { + writer->writeStartElement("ringing"); + writer->writeAttribute("xmlns", ns_jingle_rtp_info); + writer->writeEndElement(); + } + + writer->writeEndElement(); +} + +QXmppJingleCandidate::QXmppJingleCandidate() + : m_component(0), + m_foundation(0), + m_generation(0), + m_network(0), + m_port(0), + m_priority(0), + m_type(HostType) +{ +} + +/// Returns the candidate's component ID. + +int QXmppJingleCandidate::component() const +{ + return m_component; +} + +/// Sets the candidates's component ID. +/// +/// \param component + +void QXmppJingleCandidate::setComponent(int component) +{ + m_component = component; +} + +/// Returns the candidate's foundation. + +int QXmppJingleCandidate::foundation() const +{ + return m_foundation; +} + +/// Sets the candidate's foundation. +/// +/// \param foundation + +void QXmppJingleCandidate::setFoundation(int foundation) +{ + m_foundation = foundation; +} + +/// Returns the candidate's host address. +/// + +QHostAddress QXmppJingleCandidate::host() const +{ + return m_host; +} + +/// Sets the candidate's host address. +/// +/// \param host + +void QXmppJingleCandidate::setHost(const QHostAddress &host) +{ + m_host = host; +} + +/// Returns the candidate's unique identifier. +/// + +QString QXmppJingleCandidate::id() const +{ + return m_id; +} + +/// Sets the candidate's unique identifier. +/// +/// \param id + +void QXmppJingleCandidate::setId(const QString &id) +{ + m_id = id; +} + +/// Returns the network index (starting at 0) the candidate is on. +/// + +int QXmppJingleCandidate::network() const +{ + return m_network; +} + +/// Sets the network index (starting at 0) the candidate is on. +/// +/// \param network + +void QXmppJingleCandidate::setNetwork(int network) +{ + m_network = network; +} + +/// Returns the candidate's port number. +/// + +quint16 QXmppJingleCandidate::port() const +{ + return m_port; +} + +/// Sets the candidate's port number. +/// +/// \param port + +void QXmppJingleCandidate::setPort(quint16 port) +{ + m_port = port; +} + +/// Returns the candidate's priority. +/// + +int QXmppJingleCandidate::priority() const +{ + return m_priority; +} + +/// Sets the candidate's priority. +/// +/// \param priority + +void QXmppJingleCandidate::setPriority(int priority) +{ + m_priority = priority; +} + +/// Returns the candidate's protocol (e.g. "udp"). +/// + +QString QXmppJingleCandidate::protocol() const +{ + return m_protocol; +} + +/// Sets the candidate's protocol (e.g. "udp"). +/// +/// \param protocol + +void QXmppJingleCandidate::setProtocol(const QString &protocol) +{ + m_protocol = protocol; +} + +/// Returns the candidate type (e.g. "host"). +/// + +QXmppJingleCandidate::Type QXmppJingleCandidate::type() const +{ + return m_type; +} + +/// Sets the candidate type (e.g. "host"). +/// +/// \param type + +void QXmppJingleCandidate::setType(QXmppJingleCandidate::Type type) +{ + m_type = type; +} + +/// Returns true if the host address or port are empty. +/// + +bool QXmppJingleCandidate::isNull() const +{ + return m_host.isNull() || !m_port; +} + +void QXmppJingleCandidate::parse(const QDomElement &element) +{ + m_component = element.attribute("component").toInt(); + m_foundation = element.attribute("foundation").toInt(); + m_generation = element.attribute("generation").toInt(); + m_host = QHostAddress(element.attribute("ip")); + m_id = element.attribute("id"); + m_network = element.attribute("network").toInt(); + m_port = element.attribute("port").toInt(); + m_priority = element.attribute("priority").toInt(); + m_protocol = element.attribute("protocol"); + m_type = typeFromString(element.attribute("type")); +} + +void QXmppJingleCandidate::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("candidate"); + helperToXmlAddAttribute(writer, "component", QString::number(m_component)); + helperToXmlAddAttribute(writer, "foundation", QString::number(m_foundation)); + helperToXmlAddAttribute(writer, "generation", QString::number(m_generation)); + helperToXmlAddAttribute(writer, "id", m_id); + helperToXmlAddAttribute(writer, "ip", m_host.toString()); + helperToXmlAddAttribute(writer, "network", QString::number(m_network)); + helperToXmlAddAttribute(writer, "port", QString::number(m_port)); + helperToXmlAddAttribute(writer, "priority", QString::number(m_priority)); + helperToXmlAddAttribute(writer, "protocol", m_protocol); + helperToXmlAddAttribute(writer, "type", typeToString(m_type)); + writer->writeEndElement(); +} + +QXmppJingleCandidate::Type QXmppJingleCandidate::typeFromString(const QString &typeStr, bool *ok) +{ + QXmppJingleCandidate::Type type; + if (typeStr == "host") + type = HostType; + else if (typeStr == "prflx") + type = PeerReflexiveType; + else if (typeStr == "srflx") + type = ServerReflexiveType; + else if (typeStr == "relay") + type = RelayedType; + else { + qWarning() << "Unknown candidate type" << typeStr; + if (ok) + *ok = false; + return HostType; + } + if (ok) + *ok = true; + return type; +} + +QString QXmppJingleCandidate::typeToString(QXmppJingleCandidate::Type type) +{ + QString typeStr; + switch (type) + { + case HostType: + typeStr = "host"; + break; + case PeerReflexiveType: + typeStr = "prflx"; + break; + case ServerReflexiveType: + typeStr = "srflx"; + break; + case RelayedType: + typeStr = "relay"; + break; + } + return typeStr; +} + +QXmppJinglePayloadType::QXmppJinglePayloadType() + : m_channels(1), + m_clockrate(0), + m_id(0), + m_maxptime(0), + m_ptime(0) +{ +} + +/// Returns the number of channels (e.g. 1 for mono, 2 for stereo). +/// + +unsigned char QXmppJinglePayloadType::channels() const +{ + return m_channels; +} + +/// Sets the number of channels (e.g. 1 for mono, 2 for stereo). +/// +/// \param channels + +void QXmppJinglePayloadType::setChannels(unsigned char channels) +{ + m_channels = channels; +} + +/// Returns the clockrate in Hz, i.e. the number of samples per second. +/// + +unsigned int QXmppJinglePayloadType::clockrate() const +{ + return m_clockrate; +} + +/// Sets the clockrate in Hz, i.e. the number of samples per second. +/// +/// \param clockrate + +void QXmppJinglePayloadType::setClockrate(unsigned int clockrate) +{ + m_clockrate = clockrate; +} + +/// Returns the payload type identifier. +/// + +unsigned char QXmppJinglePayloadType::id() const +{ + return m_id; +} + +/// Sets the payload type identifier. +/// + +void QXmppJinglePayloadType::setId(unsigned char id) +{ + Q_ASSERT(id <= 127); + m_id = id; +} + +/// Returns the maximum packet time in milliseconds. +/// + +unsigned int QXmppJinglePayloadType::maxptime() const +{ + return m_maxptime; +} + +/// Sets the maximum packet type in milliseconds. +/// +/// \param maxptime + +void QXmppJinglePayloadType::setMaxptime(unsigned int maxptime) +{ + m_maxptime = maxptime; +} + +/// Returns the payload type name. +/// + +QString QXmppJinglePayloadType::name() const +{ + return m_name; +} + +/// Sets the payload type name. +/// +/// \param name + +void QXmppJinglePayloadType::setName(const QString &name) +{ + m_name = name; +} + +/// Returns the payload parameters. + +QMap QXmppJinglePayloadType::parameters() const +{ + return m_parameters; +} + +/// Sets the payload parameters. + +void QXmppJinglePayloadType::setParameters(const QMap ¶meters) +{ + m_parameters = parameters; +} + +/// Returns the packet time in milliseconds (20 by default). +/// + +unsigned int QXmppJinglePayloadType::ptime() const +{ + return m_ptime ? m_ptime : 20; +} + +/// Sets the packet time in milliseconds (20 by default). +/// +/// \param ptime + +void QXmppJinglePayloadType::setPtime(unsigned int ptime) +{ + m_ptime = ptime; +} + +void QXmppJinglePayloadType::parse(const QDomElement &element) +{ + m_id = element.attribute("id").toInt(); + m_name = element.attribute("name"); + m_channels = element.attribute("channels").toInt(); + if (!m_channels) + m_channels = 1; + m_clockrate = element.attribute("clockrate").toInt(); + m_maxptime = element.attribute("maxptime").toInt(); + m_ptime = element.attribute("ptime").toInt(); + + QDomElement child = element.firstChildElement("parameter"); + while (!child.isNull()) { + m_parameters.insert(child.attribute("name"), child.attribute("value")); + child = child.nextSiblingElement("parameter"); + } +} + +void QXmppJinglePayloadType::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("payload-type"); + helperToXmlAddAttribute(writer, "id", QString::number(m_id)); + helperToXmlAddAttribute(writer, "name", m_name); + if (m_channels > 1) + helperToXmlAddAttribute(writer, "channels", QString::number(m_channels)); + if (m_clockrate > 0) + helperToXmlAddAttribute(writer, "clockrate", QString::number(m_clockrate)); + if (m_maxptime > 0) + helperToXmlAddAttribute(writer, "maxptime", QString::number(m_maxptime)); + if (m_ptime > 0) + helperToXmlAddAttribute(writer, "ptime", QString::number(m_ptime)); + + foreach (const QString &key, m_parameters.keys()) { + writer->writeStartElement("parameter"); + writer->writeAttribute("name", key); + writer->writeAttribute("value", m_parameters.value(key)); + writer->writeEndElement(); + } + writer->writeEndElement(); +} + +/// Returns true if this QXmppJinglePayloadType and \a other refer to the same payload type. +/// +/// \param other + +bool QXmppJinglePayloadType::operator==(const QXmppJinglePayloadType &other) const +{ + // FIXME : what to do with m_ptime and m_maxptime? + if (m_id <= 95) + return other.m_id == m_id && other.m_clockrate == m_clockrate; + else + return other.m_channels == m_channels && + other.m_clockrate == m_clockrate && + other.m_name.toLower() == m_name.toLower(); +} diff --git a/src/base/QXmppJingleIq.h b/src/base/QXmppJingleIq.h new file mode 100644 index 00000000..ef5b66ec --- /dev/null +++ b/src/base/QXmppJingleIq.h @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPJINGLEIQ_H +#define QXMPPJINGLEIQ_H + +#include + +#include "QXmppIq.h" + +/// \brief The QXmppJinglePayloadType class represents a payload type +/// as specified by XEP-0167: Jingle RTP Sessions and RFC 5245. +/// + +class QXmppJinglePayloadType +{ +public: + QXmppJinglePayloadType(); + + unsigned char channels() const; + void setChannels(unsigned char channels); + + unsigned int clockrate() const; + void setClockrate(unsigned int clockrate); + + unsigned char id() const; + void setId(unsigned char id); + + unsigned int maxptime() const; + void setMaxptime(unsigned int maxptime); + + QString name() const; + void setName(const QString &name); + + QMap parameters() const; + void setParameters(const QMap ¶meters); + + unsigned int ptime() const; + void setPtime(unsigned int ptime); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + + bool operator==(const QXmppJinglePayloadType &other) const; + +private: + unsigned char m_channels; + unsigned int m_clockrate; + unsigned char m_id; + unsigned int m_maxptime; + QString m_name; + QMap m_parameters; + unsigned int m_ptime; +}; + +/// \brief The QXmppJingleCandidate class represents a transport candidate +/// as specified by XEP-0176: Jingle ICE-UDP Transport Method. +/// + +class QXmppJingleCandidate +{ +public: + /// This enum is used to describe a candidate's type. + enum Type + { + HostType, ///< Host candidate, a local address/port. + PeerReflexiveType, ///< Peer-reflexive candidate, + ///< the address/port as seen from the peer. + ServerReflexiveType, ///< Server-reflexive candidate, + ///< the address/port as seen by the STUN server + RelayedType, ///< Relayed candidate, a candidate from + ///< a TURN relay. + }; + + QXmppJingleCandidate(); + + int component() const; + void setComponent(int component); + + int foundation() const; + void setFoundation(int foundation); + + QHostAddress host() const; + void setHost(const QHostAddress &host); + + QString id() const; + void setId(const QString &id); + + int network() const; + void setNetwork(int network); + + quint16 port() const; + void setPort(quint16 port); + + int priority() const; + void setPriority(int priority); + + QString protocol() const; + void setProtocol(const QString &protocol); + + QXmppJingleCandidate::Type type() const; + void setType(QXmppJingleCandidate::Type); + + bool isNull() const; + + static QXmppJingleCandidate::Type typeFromString(const QString &typeStr, bool *ok = 0); + static QString typeToString(QXmppJingleCandidate::Type type); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + +private: + int m_component; + int m_foundation; + int m_generation; + QHostAddress m_host; + QString m_id; + int m_network; + quint16 m_port; + QString m_protocol; + int m_priority; + QXmppJingleCandidate::Type m_type; +}; + +/// \brief The QXmppJingleIq class represents an IQ used for initiating media +/// sessions as specified by XEP-0166: Jingle. +/// +/// \ingroup Stanzas + +class QXmppJingleIq : public QXmppIq +{ +public: + /// This enum is used to describe a Jingle action. + enum Action { + ContentAccept, + ContentAdd, + ContentModify, + ContentReject, + ContentRemove, + DescriptionInfo, + SecurityInfo, + SessionAccept, + SessionInfo, + SessionInitiate, + SessionTerminate, + TransportAccept, + TransportInfo, + TransportReject, + TransportReplace, + }; + + /// \internal + /// + /// The QXmppJingleIq::Content class represents the "content" element of a + /// QXmppJingleIq. + + class Content + { + public: + Content(); + + QString creator() const; + void setCreator(const QString &creator); + + QString name() const; + void setName(const QString &name); + + QString senders() const; + void setSenders(const QString &senders); + + // XEP-0167: Jingle RTP Sessions + QString descriptionMedia() const; + void setDescriptionMedia(const QString &media); + + void addPayloadType(const QXmppJinglePayloadType &payload); + QList payloadTypes() const; + void setPayloadTypes(const QList &payloadTypes); + + void addTransportCandidate(const QXmppJingleCandidate &candidate); + QList transportCandidates() const; + + QString transportUser() const; + void setTransportUser(const QString &user); + + QString transportPassword() const; + void setTransportPassword(const QString &password); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + + private: + QString m_creator; + QString m_disposition; + QString m_name; + QString m_senders; + + QString m_descriptionMedia; + QString m_descriptionType; + QString m_transportType; + QString m_transportUser; + QString m_transportPassword; + QList m_payloadTypes; + QList m_transportCandidates; + }; + + /// \internal + /// + /// The QXmppJingleIq::Reason class represents the "reason" element of a + /// QXmppJingleIq. + + class Reason + { + public: + enum Type { + None, + AlternativeSession, + Busy, + Cancel, + ConnectivityError, + Decline, + Expired, + FailedApplication, + FailedTransport, + GeneralError, + Gone, + IncompatibleParameters, + MediaError, + SecurityError, + Success, + Timeout, + UnsupportedApplications, + UnsupportedTransports, + }; + + Reason(); + + QString text() const; + void setText(const QString &text); + + Type type() const; + void setType(Type type); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + + private: + QString m_text; + Type m_type; + }; + + QXmppJingleIq(); + + Action action() const; + void setAction(Action action); + + QString initiator() const; + void setInitiator(const QString &initiator); + + QString responder() const; + void setResponder(const QString &responder); + + QString sid() const; + void setSid(const QString &sid); + + /// Returns a reference to the IQ's content element. + Content& content() { return m_content; }; + + /// Returns a const reference to the IQ's content element. + const Content& content() const { return m_content; }; + + /// Returns a reference to the IQ's reason element. + Reason& reason() { return m_reason; }; + + /// Returns a const reference to the IQ's reason element. + const Reason& reason() const { return m_reason; }; + + // XEP-0167: Jingle RTP Sessions + bool ringing() const; + void setRinging(bool ringing); + + /// \cond + static bool isJingleIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + Action m_action; + QString m_initiator; + QString m_responder; + QString m_sid; + + Content m_content; + Reason m_reason; + bool m_ringing; +}; + +#endif diff --git a/src/base/QXmppLogger.cpp b/src/base/QXmppLogger.cpp new file mode 100644 index 00000000..107f72d9 --- /dev/null +++ b/src/base/QXmppLogger.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include +#include +#include +#include +#include + +#include "QXmppLogger.h" + +QXmppLogger* QXmppLogger::m_logger = 0; + +static const char *typeName(QXmppLogger::MessageType type) +{ + switch (type) + { + case QXmppLogger::DebugMessage: + return "DEBUG"; + case QXmppLogger::InformationMessage: + return "INFO"; + case QXmppLogger::WarningMessage: + return "WARNING"; + case QXmppLogger::ReceivedMessage: + return "RECEIVED"; + case QXmppLogger::SentMessage: + return "SENT"; + default: + return ""; + } +} + +static QString formatted(QXmppLogger::MessageType type, const QString& text) +{ + return QDateTime::currentDateTime().toString() + " " + + QString::fromLatin1(typeName(type)) + " " + + text; +} + +/// Constructs a new QXmppLoggable. +/// +/// \param parent + +QXmppLoggable::QXmppLoggable(QObject *parent) + : QObject(parent) +{ + QXmppLoggable *logParent = qobject_cast(parent); + if (logParent) { + connect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), + logParent, SIGNAL(logMessage(QXmppLogger::MessageType,QString))); + } +} + +void QXmppLoggable::childEvent(QChildEvent *event) +{ + QXmppLoggable *child = qobject_cast(event->child()); + if (!child) + return; + + if (event->added()) { + connect(child, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), + this, SIGNAL(logMessage(QXmppLogger::MessageType,QString))); + } else if (event->removed()) { + disconnect(child, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), + this, SIGNAL(logMessage(QXmppLogger::MessageType,QString))); + } +} + +class QXmppLoggerPrivate +{ +public: + QXmppLoggerPrivate(QXmppLogger *qq); + + QXmppLogger::LoggingType loggingType; + QFile *logFile; + QString logFilePath; + QXmppLogger::MessageTypes messageTypes; + +private: + QXmppLogger *q; +}; + +QXmppLoggerPrivate::QXmppLoggerPrivate(QXmppLogger *qq) + : loggingType(QXmppLogger::NoLogging), + logFile(0), + logFilePath("QXmppClientLog.log"), + messageTypes(QXmppLogger::AnyMessage), + q(qq) +{ +} + +/// Constructs a new QXmppLogger. +/// +/// \param parent + +QXmppLogger::QXmppLogger(QObject *parent) + : QObject(parent) +{ + d = new QXmppLoggerPrivate(this); + + // make it possible to pass QXmppLogger::MessageType between threads + qRegisterMetaType< QXmppLogger::MessageType >("QXmppLogger::MessageType"); +} + +QXmppLogger::~QXmppLogger() +{ + delete d; +} + +/// Returns the default logger. +/// + +QXmppLogger* QXmppLogger::getLogger() +{ + if(!m_logger) + m_logger = new QXmppLogger(); + + return m_logger; +} + +/// Returns the handler for logging messages. +/// + +QXmppLogger::LoggingType QXmppLogger::loggingType() +{ + return d->loggingType; +} + +/// Sets the handler for logging messages. +/// +/// \param type + +void QXmppLogger::setLoggingType(QXmppLogger::LoggingType type) +{ + if (d->loggingType != type) { + d->loggingType = type; + reopen(); + } +} + +/// Returns the types of messages to log. +/// + +QXmppLogger::MessageTypes QXmppLogger::messageTypes() +{ + return d->messageTypes; +} + +/// Sets the types of messages to log. +/// +/// \param types + +void QXmppLogger::setMessageTypes(QXmppLogger::MessageTypes types) +{ + d->messageTypes = types; +} + +/// Add a logging message. +/// +/// \param type +/// \param text + +void QXmppLogger::log(QXmppLogger::MessageType type, const QString& text) +{ + // filter messages + if (!d->messageTypes.testFlag(type)) + return; + + switch(d->loggingType) + { + case QXmppLogger::FileLogging: + if (!d->logFile) { + d->logFile = new QFile(d->logFilePath); + d->logFile->open(QIODevice::WriteOnly | QIODevice::Append); + } + QTextStream(d->logFile) << formatted(type, text) << "\n"; + break; + case QXmppLogger::StdoutLogging: + std::cout << qPrintable(formatted(type, text)) << std::endl; + break; + case QXmppLogger::SignalLogging: + emit message(type, text); + break; + default: + break; + } +} + +/// Returns the path to which logging messages should be written. +/// +/// \sa loggingType() + +QString QXmppLogger::logFilePath() +{ + return d->logFilePath; +} + +/// Sets the path to which logging messages should be written. +/// +/// \param path +/// +/// \sa setLoggingType() + +void QXmppLogger::setLogFilePath(const QString &path) +{ + if (d->logFilePath != path) { + d->logFilePath = path; + reopen(); + } +} + +/// If logging to a file, causes the file to be re-opened. +/// + +void QXmppLogger::reopen() +{ + if (d->logFile) { + delete d->logFile; + d->logFile = 0; + } +} + diff --git a/src/base/QXmppLogger.h b/src/base/QXmppLogger.h new file mode 100644 index 00000000..93de33f7 --- /dev/null +++ b/src/base/QXmppLogger.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPLOGGER_H +#define QXMPPLOGGER_H + +#include + +#ifdef QXMPP_LOGGABLE_TRACE +#define qxmpp_loggable_trace(x) QString("%1(0x%2) %3").arg(metaObject()->className(), QString::number(reinterpret_cast(this), 16), x) +#else +#define qxmpp_loggable_trace(x) (x) +#endif + +class QXmppLoggerPrivate; + +/// \brief The QXmppLogger class represents a sink for logging messages. +/// +/// \ingroup Core + +class QXmppLogger : public QObject +{ + Q_OBJECT + Q_ENUMS(LoggingType) + Q_FLAGS(MessageType MessageTypes) + Q_PROPERTY(QString logFilePath READ logFilePath WRITE setLogFilePath) + Q_PROPERTY(LoggingType loggingType READ loggingType WRITE setLoggingType) + Q_PROPERTY(MessageTypes messageTypes READ messageTypes WRITE setMessageTypes) + +public: + /// This enum describes how log message are handled. + enum LoggingType + { + NoLogging = 0, ///< Log messages are discarded + FileLogging = 1, ///< Log messages are written to a file + StdoutLogging = 2, ///< Log messages are written to the standard output + SignalLogging = 4, ///< Log messages are emitted as a signal + }; + + /// This enum describes a type of log message. + enum MessageType + { + NoMessage = 0, ///< No message type + DebugMessage = 1, ///< Debugging message + InformationMessage = 2, ///< Informational message + WarningMessage = 4, ///< Warning message + ReceivedMessage = 8, ///< Message received from server + SentMessage = 16, ///< Message sent to server + AnyMessage = 31, ///< Any message type + }; + Q_DECLARE_FLAGS(MessageTypes, MessageType) + + QXmppLogger(QObject *parent = 0); + ~QXmppLogger(); + + static QXmppLogger* getLogger(); + + QXmppLogger::LoggingType loggingType(); + void setLoggingType(QXmppLogger::LoggingType type); + + QString logFilePath(); + void setLogFilePath(const QString &path); + + QXmppLogger::MessageTypes messageTypes(); + void setMessageTypes(QXmppLogger::MessageTypes types); + +public slots: + void log(QXmppLogger::MessageType type, const QString& text); + void reopen(); + +signals: + /// This signal is emitted whenever a log message is received. + void message(QXmppLogger::MessageType type, const QString &text); + +private: + static QXmppLogger* m_logger; + QXmppLoggerPrivate *d; +}; + +/// \brief The QXmppLoggable class represents a source of logging messages. +/// +/// \ingroup Core + +class QXmppLoggable : public QObject +{ + Q_OBJECT + +public: + QXmppLoggable(QObject *parent = 0); + +protected: + /// \cond + virtual void childEvent(QChildEvent *event); + /// \endcond + + /// Logs a debugging message. + /// + /// \param message + + void debug(const QString &message) + { + emit logMessage(QXmppLogger::DebugMessage, qxmpp_loggable_trace(message)); + } + + /// Logs an informational message. + /// + /// \param message + + void info(const QString &message) + { + emit logMessage(QXmppLogger::InformationMessage, qxmpp_loggable_trace(message)); + } + + /// Logs a warning message. + /// + /// \param message + + void warning(const QString &message) + { + emit logMessage(QXmppLogger::WarningMessage, qxmpp_loggable_trace(message)); + } + + /// Logs a received packet. + /// + /// \param message + + void logReceived(const QString &message) + { + emit logMessage(QXmppLogger::ReceivedMessage, qxmpp_loggable_trace(message)); + } + + /// Logs a sent packet. + /// + /// \param message + + void logSent(const QString &message) + { + emit logMessage(QXmppLogger::SentMessage, qxmpp_loggable_trace(message)); + } + +signals: + /// This signal is emitted to send logging messages. + void logMessage(QXmppLogger::MessageType type, const QString &msg); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QXmppLogger::MessageTypes) +#endif // QXMPPLOGGER_H diff --git a/src/base/QXmppMessage.cpp b/src/base/QXmppMessage.cpp new file mode 100644 index 00000000..109c0d84 --- /dev/null +++ b/src/base/QXmppMessage.cpp @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include +#include + +#include "QXmppConstants.h" +#include "QXmppMessage.h" +#include "QXmppUtils.h" + +static const char* chat_states[] = { + "", + "active", + "inactive", + "gone", + "composing", + "paused", +}; + +/// Constructs a QXmppMessage. +/// +/// \param from +/// \param to +/// \param body +/// \param thread + +QXmppMessage::QXmppMessage(const QString& from, const QString& to, const + QString& body, const QString& thread) + : QXmppStanza(from, to), + m_type(Chat), + m_stampType(QXmppMessage::DelayedDelivery), + m_state(None), + m_attentionRequested(false), + m_body(body), + m_thread(thread), + m_receiptRequested(false) +{ +} + +QXmppMessage::~QXmppMessage() +{ + +} + +/// Returns the message's body. +/// + +QString QXmppMessage::body() const +{ + return m_body; +} + +/// Sets the message's body. +/// +/// \param body + +void QXmppMessage::setBody(const QString& body) +{ + m_body = body; +} + +/// Returns true if the user's attention is requested, as defined +/// by XEP-0224: Attention. + +bool QXmppMessage::isAttentionRequested() const +{ + return m_attentionRequested; +} + +/// Sets whether the user's attention is requested, as defined +/// by XEP-0224: Attention. +/// +/// \a param requested + +void QXmppMessage::setAttentionRequested(bool requested) +{ + m_attentionRequested = requested; +} + +/// Returns true if a delivery receipt is requested, as defined +/// by XEP-0184: Message Delivery Receipts. + +bool QXmppMessage::isReceiptRequested() const +{ + return m_receiptRequested; +} + +/// Sets whether a delivery receipt is requested, as defined +/// by XEP-0184: Message Delivery Receipts. +/// +/// \a param requested + +void QXmppMessage::setReceiptRequested(bool requested) +{ + m_receiptRequested = requested; + if (requested && id().isEmpty()) + generateAndSetNextId(); +} + +/// If this message is a delivery receipt, returns the ID of the +/// original message. + +QString QXmppMessage::receiptId() const +{ + return m_receiptId; +} + +/// Make this message a delivery receipt for the message with +/// the given \a id. + +void QXmppMessage::setReceiptId(const QString &id) +{ + m_receiptId = id; +} + +/// Returns the message's type. +/// + +QXmppMessage::Type QXmppMessage::type() const +{ + return m_type; +} + +QString QXmppMessage::getTypeStr() const +{ + switch(m_type) + { + case QXmppMessage::Error: + return "error"; + case QXmppMessage::Normal: + return "normal"; + case QXmppMessage::Chat: + return "chat"; + case QXmppMessage::GroupChat: + return "groupchat"; + case QXmppMessage::Headline: + return "headline"; + default: + qWarning("QXmppMessage::getTypeStr() invalid type %d", (int)m_type); + return ""; + } +} + +/// Sets the message's type. +/// +/// \param type + +void QXmppMessage::setType(QXmppMessage::Type type) +{ + m_type = type; +} + +void QXmppMessage::setTypeFromStr(const QString& str) +{ + if(str == "error") + { + setType(QXmppMessage::Error); + return; + } + else if(str == "") // if no type is specified + { + setType(QXmppMessage::Normal); + return; + } + else if(str == "normal") + { + setType(QXmppMessage::Normal); + return; + } + else if(str == "chat") + { + setType(QXmppMessage::Chat); + return; + } + else if(str == "groupchat") + { + setType(QXmppMessage::GroupChat); + return; + } + else if(str == "headline") + { + setType(QXmppMessage::Headline); + return; + } + else + { + setType(static_cast(-1)); + qWarning("QXmppMessage::setTypeFromStr() invalid input string type: %s", + qPrintable(str)); + return; + } +} + +/// Returns the message's timestamp (if any). + +QDateTime QXmppMessage::stamp() const +{ + return m_stamp; +} + +/// Sets the message's timestamp. +/// +/// \param stamp + +void QXmppMessage::setStamp(const QDateTime &stamp) +{ + m_stamp = stamp; +} + +/// Returns the message's chat state. +/// + +QXmppMessage::State QXmppMessage::state() const +{ + return m_state; +} + +/// Sets the message's chat state. +/// +/// \param state + +void QXmppMessage::setState(QXmppMessage::State state) +{ + m_state = state; +} + +void QXmppMessage::parse(const QDomElement &element) +{ + QXmppStanza::parse(element); + + setTypeFromStr(element.attribute("type")); + m_body = element.firstChildElement("body").text(); + m_subject = element.firstChildElement("subject").text(); + m_thread = element.firstChildElement("thread").text(); + + // chat states + for (int i = Active; i <= Paused; i++) + { + QDomElement stateElement = element.firstChildElement(chat_states[i]); + if (!stateElement.isNull() && + stateElement.namespaceURI() == ns_chat_states) + { + m_state = static_cast(i); + break; + } + } + + // XEP-0184: Message Delivery Receipts + QDomElement receivedElement = element.firstChildElement("received"); + if (!receivedElement.isNull() && receivedElement.namespaceURI() == ns_message_receipts) { + m_receiptId = receivedElement.attribute("id"); + + // compatibility with old-style XEP + if (m_receiptId.isEmpty()) + m_receiptId = id(); + } else { + m_receiptId = QString(); + } + m_receiptRequested = element.firstChildElement("request").namespaceURI() == ns_message_receipts; + + // XEP-0203: Delayed Delivery + QDomElement delayElement = element.firstChildElement("delay"); + if (!delayElement.isNull() && delayElement.namespaceURI() == ns_delayed_delivery) + { + const QString str = delayElement.attribute("stamp"); + m_stamp = datetimeFromString(str); + m_stampType = QXmppMessage::DelayedDelivery; + } + + // XEP-0224: Attention + m_attentionRequested = element.firstChildElement("attention").namespaceURI() == ns_attention; + + QXmppElementList extensions; + QDomElement xElement = element.firstChildElement("x"); + while (!xElement.isNull()) + { + if (xElement.namespaceURI() == ns_legacy_delayed_delivery) + { + // XEP-0091: Legacy Delayed Delivery + const QString str = xElement.attribute("stamp"); + m_stamp = QDateTime::fromString(str, "yyyyMMddThh:mm:ss"); + m_stamp.setTimeSpec(Qt::UTC); + m_stampType = QXmppMessage::LegacyDelayedDelivery; + } else { + // other extensions + extensions << QXmppElement(xElement); + } + xElement = xElement.nextSiblingElement("x"); + } + setExtensions(extensions); +} + +void QXmppMessage::toXml(QXmlStreamWriter *xmlWriter) const +{ + + xmlWriter->writeStartElement("message"); + helperToXmlAddAttribute(xmlWriter, "xml:lang", lang()); + helperToXmlAddAttribute(xmlWriter, "id", id()); + helperToXmlAddAttribute(xmlWriter, "to", to()); + helperToXmlAddAttribute(xmlWriter, "from", from()); + helperToXmlAddAttribute(xmlWriter, "type", getTypeStr()); + if (!m_subject.isEmpty()) + helperToXmlAddTextElement(xmlWriter, "subject", m_subject); + if (!m_body.isEmpty()) + helperToXmlAddTextElement(xmlWriter, "body", m_body); + if (!m_thread.isEmpty()) + helperToXmlAddTextElement(xmlWriter, "thread", m_thread); + error().toXml(xmlWriter); + + // chat states + if (m_state > None && m_state <= Paused) + { + xmlWriter->writeStartElement(chat_states[m_state]); + xmlWriter->writeAttribute("xmlns", ns_chat_states); + xmlWriter->writeEndElement(); + } + + // time stamp + if (m_stamp.isValid()) + { + QDateTime utcStamp = m_stamp.toUTC(); + if (m_stampType == QXmppMessage::DelayedDelivery) + { + // XEP-0203: Delayed Delivery + xmlWriter->writeStartElement("delay"); + xmlWriter->writeAttribute("xmlns", ns_delayed_delivery); + helperToXmlAddAttribute(xmlWriter, "stamp", datetimeToString(utcStamp)); + xmlWriter->writeEndElement(); + } else { + // XEP-0091: Legacy Delayed Delivery + xmlWriter->writeStartElement("x"); + xmlWriter->writeAttribute("xmlns", ns_legacy_delayed_delivery); + helperToXmlAddAttribute(xmlWriter, "stamp", utcStamp.toString("yyyyMMddThh:mm:ss")); + xmlWriter->writeEndElement(); + } + } + + // XEP-0184: Message Delivery Receipts + if (!m_receiptId.isEmpty()) { + xmlWriter->writeStartElement("received"); + xmlWriter->writeAttribute("xmlns", ns_message_receipts); + xmlWriter->writeAttribute("id", m_receiptId); + xmlWriter->writeEndElement(); + } + if (m_receiptRequested) { + xmlWriter->writeStartElement("request"); + xmlWriter->writeAttribute("xmlns", ns_message_receipts); + xmlWriter->writeEndElement(); + } + + // XEP-0224: Attention + if (m_attentionRequested) { + xmlWriter->writeStartElement("attention"); + xmlWriter->writeAttribute("xmlns", ns_attention); + xmlWriter->writeEndElement(); + } + + // other extensions + foreach (const QXmppElement &extension, extensions()) + extension.toXml(xmlWriter); + xmlWriter->writeEndElement(); +} + +/// Returns the message's subject. +/// + +QString QXmppMessage::subject() const +{ + return m_subject; +} + +/// Sets the message's subject. +/// +/// \param subject + +void QXmppMessage::setSubject(const QString& subject) +{ + m_subject = subject; +} + +/// Returns the message's thread. + +QString QXmppMessage::thread() const +{ + return m_thread; +} + +/// Sets the message's thread. +/// +/// \param thread + +void QXmppMessage::setThread(const QString& thread) +{ + m_thread = thread; +} + diff --git a/src/base/QXmppMessage.h b/src/base/QXmppMessage.h new file mode 100644 index 00000000..a981f1db --- /dev/null +++ b/src/base/QXmppMessage.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPMESSAGE_H +#define QXMPPMESSAGE_H + +#include +#include "QXmppStanza.h" + +/// \brief The QXmppMessage class represents an XMPP message. +/// +/// \ingroup Stanzas +/// + +class QXmppMessage : public QXmppStanza +{ +public: + /// This enum described a message type. + enum Type + { + Error = 0, + Normal, + Chat, + GroupChat, + Headline + }; + + /// This enum describes a chat state as defined by + /// XEP-0085 : Chat State Notifications. + enum State + { + None = 0, ///< The message does not contain any chat state information. + Active, ///< User is actively participating in the chat session. + Inactive, ///< User has not been actively participating in the chat session. + Gone, ///< User has effectively ended their participation in the chat session. + Composing, ///< User is composing a message. + Paused, ///< User had been composing but now has stopped. + }; + + QXmppMessage(const QString& from = "", const QString& to = "", + const QString& body = "", const QString& thread = ""); + ~QXmppMessage(); + + QString body() const; + void setBody(const QString&); + + bool isAttentionRequested() const; + void setAttentionRequested(bool requested); + + bool isReceiptRequested() const; + void setReceiptRequested(bool requested); + + QString receiptId() const; + void setReceiptId(const QString &id); + + QDateTime stamp() const; + void setStamp(const QDateTime &stamp); + + QXmppMessage::State state() const; + void setState(QXmppMessage::State); + + QString subject() const; + void setSubject(const QString&); + + QString thread() const; + void setThread(const QString&); + + QXmppMessage::Type type() const; + void setType(QXmppMessage::Type); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + +private: + /// This enum describe a type of message timestamp. + enum StampType + { + LegacyDelayedDelivery, ///< XEP-0091: Legacy Delayed Delivery + DelayedDelivery, ///< XEP-0203: Delayed Delivery + }; + + QString getTypeStr() const; + void setTypeFromStr(const QString&); + + Type m_type; + QDateTime m_stamp; + StampType m_stampType; + State m_state; + + bool m_attentionRequested; + QString m_body; + QString m_subject; + QString m_thread; + + // Request message receipt as per XEP-0184. + QString m_receiptId; + bool m_receiptRequested; +}; + +#endif // QXMPPMESSAGE_H diff --git a/src/base/QXmppMucIq.cpp b/src/base/QXmppMucIq.cpp new file mode 100644 index 00000000..97328a2f --- /dev/null +++ b/src/base/QXmppMucIq.cpp @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include "QXmppConstants.h" +#include "QXmppMucIq.h" +#include "QXmppUtils.h" + +QXmppMucItem::QXmppMucItem() + : m_affiliation(QXmppMucItem::UnspecifiedAffiliation), + m_role(QXmppMucItem::UnspecifiedRole) +{ +} + +bool QXmppMucItem::isNull() const +{ + return m_actor.isEmpty() && + m_affiliation == UnspecifiedAffiliation && + m_jid.isEmpty() && + m_nick.isEmpty() && + m_reason.isEmpty() && + m_role == UnspecifiedRole; +} + +QString QXmppMucItem::actor() const +{ + return m_actor; +} + +void QXmppMucItem::setActor(const QString &actor) +{ + m_actor = actor; +} + +/// Returns the user's affiliation, i.e. long-lived permissions. + +QXmppMucItem::Affiliation QXmppMucItem::affiliation() const +{ + return m_affiliation; +} + +QXmppMucItem::Affiliation QXmppMucItem::affiliationFromString(const QString &affiliationStr) +{ + if (affiliationStr == "owner") + return QXmppMucItem::OwnerAffiliation; + else if (affiliationStr == "admin") + return QXmppMucItem::AdminAffiliation; + else if (affiliationStr == "member") + return QXmppMucItem::MemberAffiliation; + else if (affiliationStr == "outcast") + return QXmppMucItem::OutcastAffiliation; + else if (affiliationStr == "none") + return QXmppMucItem::NoAffiliation; + else + return QXmppMucItem::UnspecifiedAffiliation; +} + +QString QXmppMucItem::affiliationToString(Affiliation affiliation) +{ + switch (affiliation) { + case QXmppMucItem::OwnerAffiliation: + return "owner"; + case QXmppMucItem::AdminAffiliation: + return "admin"; + case QXmppMucItem::MemberAffiliation: + return "member"; + case QXmppMucItem::OutcastAffiliation: + return "outcast"; + case QXmppMucItem::NoAffiliation: + return "none"; + default: + return QString(); + } +} + +/// Sets the user's affiliation, i.e. long-lived permissions. +/// +/// \param affiliation + +void QXmppMucItem::setAffiliation(Affiliation affiliation) +{ + m_affiliation = affiliation; +} + +/// Returns the user's real JID. + +QString QXmppMucItem::jid() const +{ + return m_jid; +} + +/// Sets the user's real JID. +/// +/// \param jid + +void QXmppMucItem::setJid(const QString &jid) +{ + m_jid = jid; +} + +/// Returns the user's nickname. + +QString QXmppMucItem::nick() const +{ + return m_nick; +} + +/// Sets the user's nickname. +/// +/// \param nick + +void QXmppMucItem::setNick(const QString &nick) +{ + m_nick = nick; +} + +QString QXmppMucItem::reason() const +{ + return m_reason; +} + +void QXmppMucItem::setReason(const QString &reason) +{ + m_reason = reason; +} + +/// Returns the user's role, i.e. short-lived permissions. + +QXmppMucItem::Role QXmppMucItem::role() const +{ + return m_role; +} + +QXmppMucItem::Role QXmppMucItem::roleFromString(const QString &roleStr) +{ + if (roleStr == "moderator") + return QXmppMucItem::ModeratorRole; + else if (roleStr == "participant") + return QXmppMucItem::ParticipantRole; + else if (roleStr == "visitor") + return QXmppMucItem::VisitorRole; + else if (roleStr == "none") + return QXmppMucItem::NoRole; + else + return QXmppMucItem::UnspecifiedRole; +} + +QString QXmppMucItem::roleToString(Role role) +{ + switch (role) { + case QXmppMucItem::ModeratorRole: + return "moderator"; + case QXmppMucItem::ParticipantRole: + return "participant"; + case QXmppMucItem::VisitorRole: + return "visitor"; + case QXmppMucItem::NoRole: + return "none"; + default: + return QString(); + } +} + +/// Sets the user's role, i.e. short-lived permissions. +/// +/// \param role + +void QXmppMucItem::setRole(Role role) +{ + m_role = role; +} + +void QXmppMucItem::parse(const QDomElement &element) +{ + m_affiliation = QXmppMucItem::affiliationFromString(element.attribute("affiliation").toLower()); + m_jid = element.attribute("jid"); + m_nick = element.attribute("nick"); + m_role = QXmppMucItem::roleFromString(element.attribute("role").toLower()); + m_actor = element.firstChildElement("actor").attribute("jid"); + m_reason = element.firstChildElement("reason").text(); +} + +void QXmppMucItem::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("item"); + helperToXmlAddAttribute(writer, "affiliation", affiliationToString(m_affiliation)); + helperToXmlAddAttribute(writer, "jid", m_jid); + helperToXmlAddAttribute(writer, "nick", m_nick); + helperToXmlAddAttribute(writer, "role", roleToString(m_role)); + if (!m_actor.isEmpty()) { + writer->writeStartElement("actor"); + helperToXmlAddAttribute(writer, "jid", m_actor); + writer->writeEndElement(); + } + if (!m_reason.isEmpty()) + helperToXmlAddTextElement(writer, "reason", m_reason); + writer->writeEndElement(); +} + +/// Returns the IQ's items. + +QList QXmppMucAdminIq::items() const +{ + return m_items; +} + +/// Sets the IQ's items. +/// +/// \param items + +void QXmppMucAdminIq::setItems(const QList &items) +{ + m_items = items; +} + +bool QXmppMucAdminIq::isMucAdminIq(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + return (queryElement.namespaceURI() == ns_muc_admin); +} + +void QXmppMucAdminIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + QDomElement child = queryElement.firstChildElement("item"); + while (!child.isNull()) + { + QXmppMucItem item; + item.parse(child); + m_items << item; + child = child.nextSiblingElement("item"); + } +} + +void QXmppMucAdminIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("query"); + writer->writeAttribute("xmlns", ns_muc_admin); + foreach (const QXmppMucItem &item, m_items) + item.toXml(writer); + writer->writeEndElement(); +} + +/// Returns the IQ's data form. + +QXmppDataForm QXmppMucOwnerIq::form() const +{ + return m_form; +} + +/// Sets the IQ's data form. +/// +/// \param form + +void QXmppMucOwnerIq::setForm(const QXmppDataForm &form) +{ + m_form = form; +} + +bool QXmppMucOwnerIq::isMucOwnerIq(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + return (queryElement.namespaceURI() == ns_muc_owner); +} + +void QXmppMucOwnerIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + m_form.parse(queryElement.firstChildElement("x")); +} + +void QXmppMucOwnerIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("query"); + writer->writeAttribute("xmlns", ns_muc_owner); + m_form.toXml(writer); + writer->writeEndElement(); +} + diff --git a/src/base/QXmppMucIq.h b/src/base/QXmppMucIq.h new file mode 100644 index 00000000..5e73fc9b --- /dev/null +++ b/src/base/QXmppMucIq.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPMUCIQ_H +#define QXMPPMUCIQ_H + +#include "QXmppDataForm.h" +#include "QXmppIq.h" + +/// \brief The QXmppMucItem class represents a chat room "item". +/// +/// It is used to convey information such as permissions. +/// +/// \ingroup Stanzas + +class QXmppMucItem +{ +public: + /// This enum is used to represent long-lived permissions in a room (affiliations). + enum Affiliation { + UnspecifiedAffiliation, + OutcastAffiliation, + NoAffiliation, + MemberAffiliation, + AdminAffiliation, + OwnerAffiliation, + }; + + /// This enum is used to represent short-lived permissions in a room (roles). + enum Role { + UnspecifiedRole, + NoRole, + VisitorRole, + ParticipantRole, + ModeratorRole, + }; + + QXmppMucItem(); + bool isNull() const; + + QString actor() const; + void setActor(const QString &actor); + + Affiliation affiliation() const; + void setAffiliation(Affiliation affiliation); + + QString jid() const; + void setJid(const QString &jid); + + QString nick() const; + void setNick(const QString &nick); + + QString reason() const; + void setReason(const QString &reason); + + Role role() const; + void setRole(Role role); + + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + + /// \cond + static Affiliation affiliationFromString(const QString &affiliationStr); + static QString affiliationToString(Affiliation affiliation); + static Role roleFromString(const QString &roleStr); + static QString roleToString(Role role); + /// \endcond +private: + QString m_actor; + Affiliation m_affiliation; + QString m_jid; + QString m_nick; + QString m_reason; + Role m_role; +}; + +/// \brief The QXmppMucAdminIq class represents a chat room administration IQ +/// as defined by XEP-0045: Multi-User Chat. +/// +/// It is used to get or modify room memberships. +/// +/// \ingroup Stanzas + +class QXmppMucAdminIq : public QXmppIq +{ +public: + QList items() const; + void setItems(const QList &items); + + /// \cond + static bool isMucAdminIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QList m_items; +}; + +/// \brief The QXmppMucOwnerIq class represents a chat room configuration IQ as +/// defined by XEP-0045: Multi-User Chat. +/// +/// It is used to get or modify room configuration options. +/// +/// \sa QXmppDataForm +/// + +class QXmppMucOwnerIq : public QXmppIq +{ +public: + QXmppDataForm form() const; + void setForm(const QXmppDataForm &form); + + /// \cond + static bool isMucOwnerIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QXmppDataForm m_form; +}; + +#endif diff --git a/src/base/QXmppNonSASLAuth.cpp b/src/base/QXmppNonSASLAuth.cpp new file mode 100644 index 00000000..0dea6184 --- /dev/null +++ b/src/base/QXmppNonSASLAuth.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include +#include +#include + +#include "QXmppConstants.h" +#include "QXmppNonSASLAuth.h" +#include "QXmppUtils.h" + +QXmppNonSASLAuthIq::QXmppNonSASLAuthIq() + : QXmppIq(QXmppIq::Set) +{ +} + +bool QXmppNonSASLAuthIq::isNonSASLAuthIq(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + return queryElement.namespaceURI() == ns_auth; +} + +void QXmppNonSASLAuthIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + m_username = queryElement.firstChildElement("username").text(); + m_password = queryElement.firstChildElement("password").text(); + m_digest = QByteArray::fromHex(queryElement.firstChildElement("digest").text().toAscii()); + m_resource = queryElement.firstChildElement("resource").text(); +} + +void QXmppNonSASLAuthIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("query"); + writer->writeAttribute("xmlns", ns_auth); + if (!m_username.isEmpty()) + writer->writeTextElement("username", m_username); + if (!m_digest.isEmpty()) + writer->writeTextElement("digest", m_digest.toHex()); + if (!m_password.isEmpty()) + writer->writeTextElement("password", m_password); + if (!m_resource.isEmpty()) + writer->writeTextElement("resource", m_resource); + writer->writeEndElement(); +} + +QString QXmppNonSASLAuthIq::username() const +{ + return m_username; +} + +void QXmppNonSASLAuthIq::setUsername( const QString &username ) +{ + m_username = username; +} + +QByteArray QXmppNonSASLAuthIq::digest() const +{ + return m_digest; +} + +void QXmppNonSASLAuthIq::setDigest(const QString &streamId, const QString &password) +{ + m_digest = QCryptographicHash::hash(streamId.toUtf8() + password.toUtf8(), QCryptographicHash::Sha1); +} + +QString QXmppNonSASLAuthIq::password() const +{ + return m_password; +} + +void QXmppNonSASLAuthIq::setPassword( const QString &password ) +{ + m_password = password; +} + +QString QXmppNonSASLAuthIq::resource() const +{ + return m_resource; +} + +void QXmppNonSASLAuthIq::setResource(const QString &resource) +{ + m_resource = resource; +} + diff --git a/src/base/QXmppNonSASLAuth.h b/src/base/QXmppNonSASLAuth.h new file mode 100644 index 00000000..a17436e7 --- /dev/null +++ b/src/base/QXmppNonSASLAuth.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXmppNonSASLAuth_H +#define QXmppNonSASLAuth_H + +#include "QXmppIq.h" + +class QXmppNonSASLAuthIq : public QXmppIq +{ +public: + QXmppNonSASLAuthIq(); + + QString username() const; + void setUsername(const QString &username); + + QByteArray digest() const; + void setDigest(const QString &streamId, const QString &password); + + QString password() const; + void setPassword(const QString &password); + + QString resource() const; + void setResource(const QString &resource); + + static bool isNonSASLAuthIq(const QDomElement &element); + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString m_username; + QByteArray m_digest; + QString m_password; + QString m_resource; +}; + +#endif // QXmppNonSASLAuth_H diff --git a/src/base/QXmppPacket.cpp b/src/base/QXmppPacket.cpp new file mode 100644 index 00000000..1d284325 --- /dev/null +++ b/src/base/QXmppPacket.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#include "QXmppPacket.h" + +QXmppPacket::QXmppPacket() +{ +} + +QXmppPacket::~QXmppPacket() +{ +} + diff --git a/src/base/QXmppPacket.h b/src/base/QXmppPacket.h new file mode 100644 index 00000000..427217c7 --- /dev/null +++ b/src/base/QXmppPacket.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPPACKET_H +#define QXMPPPACKET_H + +#include + +// forward declarations of QXmlStream* classes will not work on Mac, we need to +// include the whole header. +// See http://lists.trolltech.com/qt-interest/2008-07/thread00798-0.html +// for an explanation. +#include + +class QDomElement; + +class QXmppPacket +{ +public: + QXmppPacket(); + virtual ~QXmppPacket(); + + virtual void parse(const QDomElement &element) = 0; + virtual void toXml( QXmlStreamWriter *writer ) const = 0; +}; + +#endif // QXMPPPACKET_H diff --git a/src/base/QXmppPingIq.cpp b/src/base/QXmppPingIq.cpp new file mode 100644 index 00000000..7058c6d0 --- /dev/null +++ b/src/base/QXmppPingIq.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include "QXmppConstants.h" +#include "QXmppPingIq.h" +#include "QXmppUtils.h" + +#include + +QXmppPingIq::QXmppPingIq() : QXmppIq(QXmppIq::Get) +{ +} + +bool QXmppPingIq::isPingIq(const QDomElement &element) +{ + QDomElement pingElement = element.firstChildElement("ping"); + return (element.attribute("type") == "get" && + pingElement.namespaceURI() == ns_ping); +} + +void QXmppPingIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("ping"); + writer->writeAttribute("xmlns", ns_ping); + writer->writeEndElement(); +} + diff --git a/src/base/QXmppPingIq.h b/src/base/QXmppPingIq.h new file mode 100644 index 00000000..527eeb68 --- /dev/null +++ b/src/base/QXmppPingIq.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPPINGIQ_H +#define QXMPPPINGIQ_H + +#include "QXmppIq.h" + +class QXmlStreamWriter; +class QDomElement; + +class QXmppPingIq : public QXmppIq +{ +public: + QXmppPingIq(); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + static bool isPingIq(const QDomElement &element); +}; + +#endif diff --git a/src/base/QXmppPresence.cpp b/src/base/QXmppPresence.cpp new file mode 100644 index 00000000..b967c8e5 --- /dev/null +++ b/src/base/QXmppPresence.cpp @@ -0,0 +1,510 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#include "QXmppPresence.h" +#include "QXmppUtils.h" +#include +#include +#include +#include "QXmppConstants.h" + +/// Constructs a QXmppPresence. +/// +/// \param type +/// \param status + +QXmppPresence::QXmppPresence(QXmppPresence::Type type, + const QXmppPresence::Status& status) + : QXmppStanza(), + m_type(type), + m_status(status), + m_vCardUpdateType(VCardUpdateNone) +{ + +} + +/// Destroys a QXmppPresence. + +QXmppPresence::~QXmppPresence() +{ + +} + +/// Returns the presence type. +/// +/// You can use this method to determine the action which needs to be +/// taken in response to receiving the presence. For instance, if the type is +/// QXmppPresence::Available or QXmppPresence::Unavailable, you could update +/// the icon representing a contact's availability. + +QXmppPresence::Type QXmppPresence::type() const +{ + return m_type; +} + +/// Sets the presence type. +/// +/// \param type + +void QXmppPresence::setType(QXmppPresence::Type type) +{ + m_type = type; +} + +/// Returns the presence status. + +const QXmppPresence::Status& QXmppPresence::status() const +{ + return m_status; +} + +/// Returns a reference to the presence status, allowing you to change it. + +QXmppPresence::Status& QXmppPresence::status() +{ + return m_status; +} + +/// Sets the presence status. +/// +/// \param status + +void QXmppPresence::setStatus(const QXmppPresence::Status& status) +{ + m_status = status; +} + +void QXmppPresence::parse(const QDomElement &element) +{ + QXmppStanza::parse(element); + + setTypeFromStr(element.attribute("type")); + m_status.parse(element); + + QXmppElementList extensions; + QDomElement xElement = element.firstChildElement(); + m_vCardUpdateType = VCardUpdateNone; + while(!xElement.isNull()) + { + // XEP-0045: Multi-User Chat + if(xElement.namespaceURI() == ns_muc_user) + { + QDomElement itemElement = xElement.firstChildElement("item"); + m_mucItem.parse(itemElement); + QDomElement statusElement = xElement.firstChildElement("status"); + m_mucStatusCodes.clear(); + while (!statusElement.isNull()) { + m_mucStatusCodes << statusElement.attribute("code").toInt(); + statusElement = statusElement.nextSiblingElement("status"); + } + } + // XEP-0153: vCard-Based Avatars + else if(xElement.namespaceURI() == ns_vcard_update) + { + QDomElement photoElement = xElement.firstChildElement("photo"); + if(!photoElement.isNull()) + { + m_photoHash = QByteArray::fromHex(photoElement.text().toAscii()); + if(m_photoHash.isEmpty()) + m_vCardUpdateType = VCardUpdateNoPhoto; + else + m_vCardUpdateType = VCardUpdateValidPhoto; + } + else + { + m_photoHash = QByteArray(); + m_vCardUpdateType = VCardUpdateNotReady; + } + } + // XEP-0115: Entity Capabilities + else if(xElement.tagName() == "c" && xElement.namespaceURI() == ns_capabilities) + { + m_capabilityNode = xElement.attribute("node"); + m_capabilityVer = QByteArray::fromBase64(xElement.attribute("ver").toAscii()); + m_capabilityHash = xElement.attribute("hash"); + m_capabilityExt = xElement.attribute("ext").split(" ", QString::SkipEmptyParts); + } + else if (xElement.tagName() == "error") + { + } + else if (xElement.tagName() == "show") + { + } + else if (xElement.tagName() == "status") + { + } + else if (xElement.tagName() == "priority") + { + } + else + { + // other extensions + extensions << QXmppElement(xElement); + } + xElement = xElement.nextSiblingElement(); + } + setExtensions(extensions); +} + +void QXmppPresence::toXml(QXmlStreamWriter *xmlWriter) const +{ + xmlWriter->writeStartElement("presence"); + helperToXmlAddAttribute(xmlWriter,"xml:lang", lang()); + helperToXmlAddAttribute(xmlWriter,"id", id()); + helperToXmlAddAttribute(xmlWriter,"to", to()); + helperToXmlAddAttribute(xmlWriter,"from", from()); + helperToXmlAddAttribute(xmlWriter,"type", getTypeStr()); + m_status.toXml(xmlWriter); + + error().toXml(xmlWriter); + + // XEP-0045: Multi-User Chat + if(!m_mucItem.isNull() || !m_mucStatusCodes.isEmpty()) + { + xmlWriter->writeStartElement("x"); + xmlWriter->writeAttribute("xmlns", ns_muc_user); + if (!m_mucItem.isNull()) + m_mucItem.toXml(xmlWriter); + foreach (int code, m_mucStatusCodes) { + xmlWriter->writeStartElement("status"); + xmlWriter->writeAttribute("code", QString::number(code)); + xmlWriter->writeEndElement(); + } + xmlWriter->writeEndElement(); + } + + // XEP-0153: vCard-Based Avatars + if(m_vCardUpdateType != VCardUpdateNone) + { + xmlWriter->writeStartElement("x"); + xmlWriter->writeAttribute("xmlns", ns_vcard_update); + switch(m_vCardUpdateType) + { + case VCardUpdateNoPhoto: + helperToXmlAddTextElement(xmlWriter, "photo", ""); + break; + case VCardUpdateValidPhoto: + helperToXmlAddTextElement(xmlWriter, "photo", m_photoHash.toHex()); + break; + case VCardUpdateNotReady: + break; + default: + break; + } + xmlWriter->writeEndElement(); + } + + if(!m_capabilityNode.isEmpty() && !m_capabilityVer.isEmpty() + && !m_capabilityHash.isEmpty()) + { + xmlWriter->writeStartElement("c"); + xmlWriter->writeAttribute("xmlns", ns_capabilities); + helperToXmlAddAttribute(xmlWriter, "hash", m_capabilityHash); + helperToXmlAddAttribute(xmlWriter, "node", m_capabilityNode); + helperToXmlAddAttribute(xmlWriter, "ver", m_capabilityVer.toBase64()); + xmlWriter->writeEndElement(); + } + + foreach (const QXmppElement &extension, extensions()) + extension.toXml(xmlWriter); + + xmlWriter->writeEndElement(); +} + +QString QXmppPresence::getTypeStr() const +{ + switch(m_type) { + case QXmppPresence::Error: + return "error"; + case QXmppPresence::Available: + return ""; + case QXmppPresence::Unavailable: + return "unavailable"; + case QXmppPresence::Subscribe: + return "subscribe"; + case QXmppPresence::Subscribed: + return "subscribed"; + case QXmppPresence::Unsubscribe: + return "unsubscribe"; + case QXmppPresence::Unsubscribed: + return "unsubscribed"; + case QXmppPresence::Probe: + return "probe"; + default: + qWarning("QXmppPresence::getTypeStr() invalid type %d", (int)m_type); + return ""; + } +} + +void QXmppPresence::setTypeFromStr(const QString& str) +{ + if(str == "error") + m_type = QXmppPresence::Error; + else if(str == "") + m_type = QXmppPresence::Available; + else if(str == "unavailable") + m_type = QXmppPresence::Unavailable; + else if(str == "subscribe") + m_type = QXmppPresence::Subscribe; + else if(str == "subscribed") + m_type = QXmppPresence::Subscribed; + else if(str == "unsubscribe") + m_type = QXmppPresence::Unsubscribe; + else if(str == "unsubscribed") + m_type = QXmppPresence::Unsubscribed; + else if(str == "probe") + m_type = QXmppPresence::Probe; + else { + qWarning("QXmppPresence::setTypeFromStr() invalid input string type: %s", + qPrintable(str)); + m_type = QXmppPresence::Error; + } +} + +/// Constructs a presence status. + +QXmppPresence::Status::Status(QXmppPresence::Status::Type type, + const QString statusText, int priority) : + m_type(type), + m_statusText(statusText), m_priority(priority) +{ +} + +/// Returns the status type, for instance busy or away. + +QXmppPresence::Status::Type QXmppPresence::Status::type() const +{ + return m_type; +} + +/// Sets the status type. + +void QXmppPresence::Status::setType(QXmppPresence::Status::Type type) +{ + m_type = type; +} + +void QXmppPresence::Status::setTypeFromStr(const QString& str) +{ + // FIXME: there is no keyword for Offline + if(str == "") + m_type = QXmppPresence::Status::Online; + else if(str == "away") + m_type = QXmppPresence::Status::Away; + else if(str == "chat") + m_type = QXmppPresence::Status::Chat; + else if(str == "dnd") + m_type = QXmppPresence::Status::DND; + else if(str == "xa") + m_type = QXmppPresence::Status::XA; + else { + qWarning("QXmppPresence::Status::setTypeFromStr() invalid input string type %s", + qPrintable(str)); + m_type = QXmppPresence::Status::Online; + } +} + +QString QXmppPresence::Status::getTypeStr() const +{ + switch(m_type) { + case QXmppPresence::Status::Online: + return ""; + case QXmppPresence::Status::Offline: + // FIXME: there is no keyword for Offline + return ""; + case QXmppPresence::Status::Away: + return "away"; + case QXmppPresence::Status::XA: + return "xa"; + case QXmppPresence::Status::DND: + return "dnd"; + case QXmppPresence::Status::Chat: + return "chat"; + default: + qWarning("QXmppPresence::Status::getTypeStr() invalid type %d", + (int)m_type); + return ""; + } +} + +/// Returns the status text, a textual description of the user's status. + +QString QXmppPresence::Status::statusText() const +{ + return m_statusText; +} + +/// Sets the status text, a textual description of the user's status. +/// +/// \param str The status text, for example "Gone fishing". + +void QXmppPresence::Status::setStatusText(const QString& str) +{ + m_statusText = str; +} + +/// Returns the priority level of the resource. + +int QXmppPresence::Status::priority() const +{ + return m_priority; +} + +/// Sets the priority level of the resource. +/// +/// \param priority + +void QXmppPresence::Status::setPriority(int priority) +{ + m_priority = priority; +} + +void QXmppPresence::Status::parse(const QDomElement &element) +{ + setTypeFromStr(element.firstChildElement("show").text()); + m_statusText = element.firstChildElement("status").text(); + m_priority = element.firstChildElement("priority").text().toInt(); +} + +void QXmppPresence::Status::toXml(QXmlStreamWriter *xmlWriter) const +{ + const QString show = getTypeStr(); + if (!show.isEmpty()) + helperToXmlAddTextElement(xmlWriter, "show", getTypeStr()); + if (!m_statusText.isEmpty()) + helperToXmlAddTextElement(xmlWriter, "status", m_statusText); + if (m_priority != 0) + helperToXmlAddTextElement(xmlWriter, "priority", QString::number(m_priority)); +} + +/// Returns the photo-hash of the VCardUpdate. +/// +/// \return QByteArray + +QByteArray QXmppPresence::photoHash() const +{ + return m_photoHash; +} + +/// Sets the photo-hash of the VCardUpdate. +/// +/// \param photoHash as QByteArray + +void QXmppPresence::setPhotoHash(const QByteArray& photoHash) +{ + m_photoHash = photoHash; +} + +/// Returns the type of VCardUpdate +/// +/// \return VCardUpdateType + +QXmppPresence::VCardUpdateType QXmppPresence::vCardUpdateType() const +{ + return m_vCardUpdateType; +} + +/// Sets the type of VCardUpdate +/// +/// \param type VCardUpdateType + +void QXmppPresence::setVCardUpdateType(VCardUpdateType type) +{ + m_vCardUpdateType = type; +} + +/// XEP-0115: Entity Capabilities +QString QXmppPresence::capabilityHash() const +{ + return m_capabilityHash; +} + +/// XEP-0115: Entity Capabilities +void QXmppPresence::setCapabilityHash(const QString& hash) +{ + m_capabilityHash = hash; +} + +/// XEP-0115: Entity Capabilities +QString QXmppPresence::capabilityNode() const +{ + return m_capabilityNode; +} + +/// XEP-0115: Entity Capabilities +void QXmppPresence::setCapabilityNode(const QString& node) +{ + m_capabilityNode = node; +} + +/// XEP-0115: Entity Capabilities +QByteArray QXmppPresence::capabilityVer() const +{ + return m_capabilityVer; +} + +/// XEP-0115: Entity Capabilities +void QXmppPresence::setCapabilityVer(const QByteArray& ver) +{ + m_capabilityVer = ver; +} + +/// Legacy XEP-0115: Entity Capabilities +QStringList QXmppPresence::capabilityExt() const +{ + return m_capabilityExt; +} + +/// Returns the MUC item. + +QXmppMucItem QXmppPresence::mucItem() const +{ + return m_mucItem; +} + +/// Sets the MUC item. +/// +/// \param item + +void QXmppPresence::setMucItem(const QXmppMucItem &item) +{ + m_mucItem = item; +} + +/// Returns the MUC status codes. + +QList QXmppPresence::mucStatusCodes() const +{ + return m_mucStatusCodes; +} + +/// Sets the MUC status codes. +/// +/// \param codes + +void QXmppPresence::setMucStatusCodes(const QList &codes) +{ + m_mucStatusCodes = codes; +} + diff --git a/src/base/QXmppPresence.h b/src/base/QXmppPresence.h new file mode 100644 index 00000000..8b85e01b --- /dev/null +++ b/src/base/QXmppPresence.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPPRESENCE_H +#define QXMPPPRESENCE_H + +#include "QXmppStanza.h" +#include "QXmppMucIq.h" + +/// \brief The QXmppPresence class represents an XMPP presence stanza. +/// +/// \ingroup Stanzas +class QXmppPresence : public QXmppStanza +{ +public: + /// This enum is used to describe a presence type. + enum Type + { + Error = 0, ///< An error has occurred regarding processing or delivery of a previously-sent presence stanza. + Available, ///< Signals that the sender is online and available for communication. + Unavailable, ///< Signals that the sender is no longer available for communication. + Subscribe, ///< The sender wishes to subscribe to the recipient's presence. + Subscribed, ///< The sender has allowed the recipient to receive their presence. + Unsubscribe, ///< The sender is unsubscribing from another entity's presence. + Unsubscribed, ///< The subscription request has been denied or a previously-granted subscription has been cancelled. + Probe ///< A request for an entity's current presence; SHOULD be generated only by a server on behalf of a user. + }; + + // XEP-0153: vCard-Based Avatars + enum VCardUpdateType + { + VCardUpdateNone = 0, ///< Protocol is not supported + VCardUpdateNoPhoto, ///< User is not using any image + VCardUpdateValidPhoto, ///< User is advertising an image + VCardUpdateNotReady ///< User is not ready to advertise an image + +/// \note This enables recipients to distinguish between the absence of an image +/// (empty photo element) and mere support for the protocol (empty update child). + }; + + /// \brief The QXmppPresence::Status class represents the status of an XMPP entity. + /// + /// It stores information such as the "away", "busy" status of a user, or + /// a human-readable description. + + class Status + { + public: + /// This enum is used to describe an availability status. + enum Type + { + Offline = 0, + Online, ///< The entity or resource is online. + Away, ///< The entity or resource is temporarily away. + XA, ///< The entity or resource is away for an extended period. + DND, ///< The entity or resource is busy ("Do Not Disturb"). + Chat, ///< The entity or resource is actively interested in chatting. + }; + + Status(QXmppPresence::Status::Type type = QXmppPresence::Status::Online, + const QString statusText = "", int priority = 0); + + QXmppPresence::Status::Type type() const; + void setType(QXmppPresence::Status::Type); + + QString statusText() const; + void setStatusText(const QString&); + + int priority() const; + void setPriority(int); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + + private: + QString getTypeStr() const; + void setTypeFromStr(const QString&); + + QXmppPresence::Status::Type m_type; + QString m_statusText; + int m_priority; + }; + + QXmppPresence(QXmppPresence::Type type = QXmppPresence::Available, + const QXmppPresence::Status& status = QXmppPresence::Status()); + ~QXmppPresence(); + + QXmppPresence::Type type() const; + void setType(QXmppPresence::Type); + + QXmppPresence::Status& status(); + const QXmppPresence::Status& status() const; + void setStatus(const QXmppPresence::Status&); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + + // XEP-0045: Multi-User Chat + QXmppMucItem mucItem() const; + void setMucItem(const QXmppMucItem &item); + + QList mucStatusCodes() const; + void setMucStatusCodes(const QList &codes); + + /// XEP-0153: vCard-Based Avatars + QByteArray photoHash() const; + void setPhotoHash(const QByteArray&); + + VCardUpdateType vCardUpdateType() const; + void setVCardUpdateType(VCardUpdateType type); + + // XEP-0115: Entity Capabilities + QString capabilityHash() const; + void setCapabilityHash(const QString&); + + QString capabilityNode() const; + void setCapabilityNode(const QString&); + + QByteArray capabilityVer() const; + void setCapabilityVer(const QByteArray&); + + QStringList capabilityExt() const; + +private: + QString getTypeStr() const; + void setTypeFromStr(const QString&); + + Type m_type; + QXmppPresence::Status m_status; + + + /// XEP-0153: vCard-Based Avatars + + /// m_photoHash: the SHA1 hash of the avatar image data itself (not the base64-encoded version) + /// in accordance with RFC 3174 + QByteArray m_photoHash; + VCardUpdateType m_vCardUpdateType; + + // XEP-0115: Entity Capabilities + QString m_capabilityHash; + QString m_capabilityNode; + QByteArray m_capabilityVer; + // Legacy XEP-0115: Entity Capabilities + QStringList m_capabilityExt; + + // XEP-0045: Multi-User Chat + QXmppMucItem m_mucItem; + QList m_mucStatusCodes; +}; + +#endif // QXMPPPRESENCE_H diff --git a/src/base/QXmppPubSubIq.cpp b/src/base/QXmppPubSubIq.cpp new file mode 100644 index 00000000..1ad1c39d --- /dev/null +++ b/src/base/QXmppPubSubIq.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include "QXmppConstants.h" +#include "QXmppPubSubIq.h" +#include "QXmppUtils.h" + +static const char *ns_pubsub = "http://jabber.org/protocol/pubsub"; + +static const char *pubsub_queries[] = { + "affiliations", + "default", + "items", + "publish", + "retract", + "subscribe", + "subscription", + "subscriptions", + "unsubscribe", +}; + +/// Returns the ID of the PubSub item. +/// + +QString QXmppPubSubItem::id() const +{ + return m_id; +} + +/// Sets the ID of the PubSub item. +/// +/// \param id + +void QXmppPubSubItem::setId(const QString &id) +{ + m_id = id; +} + +/// Returns the contents of the PubSub item. +/// + +QXmppElement QXmppPubSubItem::contents() const +{ + return m_contents; +} + +/// Sets the contents of the PubSub item. +/// +/// \param contents + +void QXmppPubSubItem::setContents(const QXmppElement &contents) +{ + m_contents = contents; +} + +void QXmppPubSubItem::parse(const QDomElement &element) +{ + m_id = element.attribute("id"); + m_contents = QXmppElement(element.firstChildElement()); +} + +void QXmppPubSubItem::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("item"); + helperToXmlAddAttribute(writer, "id", m_id); + m_contents.toXml(writer); + writer->writeEndElement(); +} + +/// Returns the PubSub queryType for this IQ. +/// + +QXmppPubSubIq::QueryType QXmppPubSubIq::queryType() const +{ + return m_queryType; +} + +/// Sets the PubSub queryType for this IQ. +/// +/// \param queryType + +void QXmppPubSubIq::setQueryType(QXmppPubSubIq::QueryType queryType) +{ + m_queryType = queryType; +} + +/// Returns the JID being queried. +/// + +QString QXmppPubSubIq::queryJid() const +{ + return m_queryJid; +} + +/// Sets the JID being queried. +/// +/// \param queryJid + +void QXmppPubSubIq::setQueryJid(const QString &queryJid) +{ + m_queryJid = queryJid; +} + +/// Returns the node being queried. +/// + +QString QXmppPubSubIq::queryNode() const +{ + return m_queryNode; +} + +/// Sets the node being queried. +/// +/// \param queryNode + +void QXmppPubSubIq::setQueryNode(const QString &queryNode) +{ + m_queryNode = queryNode; +} + +/// Returns the subscription ID. +/// + +QString QXmppPubSubIq::subscriptionId() const +{ + return m_subscriptionId; +} + +/// Sets the subscription ID. +/// +/// \param subscriptionId + +void QXmppPubSubIq::setSubscriptionId(const QString &subscriptionId) +{ + m_subscriptionId = subscriptionId; +} + +/// Returns the IQ's items. +/// + +QList QXmppPubSubIq::items() const +{ + return m_items; +} + +/// Sets the IQ's items. +/// +/// \param items + +void QXmppPubSubIq::setItems(const QList &items) +{ + m_items = items; +} + +bool QXmppPubSubIq::isPubSubIq(const QDomElement &element) +{ + const QDomElement pubSubElement = element.firstChildElement("pubsub"); + return pubSubElement.namespaceURI() == ns_pubsub; +} + +void QXmppPubSubIq::parseElementFromChild(const QDomElement &element) +{ + const QDomElement pubSubElement = element.firstChildElement("pubsub"); + + const QDomElement queryElement = pubSubElement.firstChildElement(); + + // determine query type + const QString tagName = queryElement.tagName(); + for (int i = ItemsQuery; i <= SubscriptionsQuery; i++) + { + if (tagName == pubsub_queries[i]) + { + m_queryType = static_cast(i); + break; + } + } + m_queryJid = queryElement.attribute("jid"); + m_queryNode = queryElement.attribute("node"); + + // parse contents + QDomElement childElement; + switch (m_queryType) + { + case QXmppPubSubIq::ItemsQuery: + case QXmppPubSubIq::PublishQuery: + childElement = queryElement.firstChildElement("item"); + while (!childElement.isNull()) + { + QXmppPubSubItem item; + item.parse(childElement); + m_items << item; + childElement = childElement.nextSiblingElement("item"); + } + break; + case QXmppPubSubIq::SubscriptionQuery: + m_subscriptionId = queryElement.attribute("subid"); + m_subscriptionType = queryElement.attribute("subscription"); + break; + default: + break; + } +} + +void QXmppPubSubIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("pubsub"); + writer->writeAttribute("xmlns", ns_pubsub); + + // write query type + writer->writeStartElement(pubsub_queries[m_queryType]); + helperToXmlAddAttribute(writer, "jid", m_queryJid); + helperToXmlAddAttribute(writer, "node", m_queryNode); + + // write contents + switch (m_queryType) + { + case QXmppPubSubIq::ItemsQuery: + case QXmppPubSubIq::PublishQuery: + foreach (const QXmppPubSubItem &item, m_items) + item.toXml(writer); + break; + case QXmppPubSubIq::SubscriptionQuery: + helperToXmlAddAttribute(writer, "subid", m_subscriptionId); + helperToXmlAddAttribute(writer, "subscription", m_subscriptionType); + break; + default: + break; + } + writer->writeEndElement(); + writer->writeEndElement(); +} diff --git a/src/base/QXmppPubSubIq.h b/src/base/QXmppPubSubIq.h new file mode 100644 index 00000000..01dc3a92 --- /dev/null +++ b/src/base/QXmppPubSubIq.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPPUBSUBIQ_H +#define QXMPPPUBSUBIQ_H + +#include "QXmppIq.h" + +/// \brief The QXmppPubSubItem class represents a publish-subscribe item +/// as defined by XEP-0060: Publish-Subscribe. +/// + +class QXmppPubSubItem +{ +public: + QString id() const; + void setId(const QString &id); + + QXmppElement contents() const; + void setContents(const QXmppElement &contents); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString m_id; + QXmppElement m_contents; +}; + +/// \brief The QXmppPubSubIq class represents an IQ used for the +/// publish-subscribe mechanisms defined by XEP-0060: Publish-Subscribe. +/// +/// \ingroup Stanzas + +class QXmppPubSubIq : public QXmppIq +{ +public: + /// This enum is used to describe a publish-subscribe query type. + enum QueryType + { + AffiliationsQuery, + DefaultQuery, + ItemsQuery, + PublishQuery, + RetractQuery, + SubscribeQuery, + SubscriptionQuery, + SubscriptionsQuery, + UnsubscribeQuery, + }; + + QXmppPubSubIq::QueryType queryType() const; + void setQueryType(QXmppPubSubIq::QueryType queryType); + + QString queryJid() const; + void setQueryJid(const QString &jid); + + QString queryNode() const; + void setQueryNode(const QString &node); + + QList items() const; + void setItems(const QList &items); + + QString subscriptionId() const; + void setSubscriptionId(const QString &id); + + /// \cond + static bool isPubSubIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement&); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QXmppPubSubIq::QueryType m_queryType; + QString m_queryJid; + QString m_queryNode; + QList m_items; + QString m_subscriptionId; + QString m_subscriptionType; +}; + +#endif diff --git a/src/base/QXmppRosterIq.cpp b/src/base/QXmppRosterIq.cpp new file mode 100644 index 00000000..0b2e1716 --- /dev/null +++ b/src/base/QXmppRosterIq.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include +#include + +#include "QXmppRosterIq.h" +#include "QXmppConstants.h" +#include "QXmppUtils.h" + +/// Adds an item to the roster IQ. +/// +/// \param item + +void QXmppRosterIq::addItem(const Item& item) +{ + m_items.append(item); +} + +/// Returns the roster IQ's items. + +QList QXmppRosterIq::items() const +{ + return m_items; +} + +bool QXmppRosterIq::isRosterIq(const QDomElement &element) +{ + return (element.firstChildElement("query").namespaceURI() == ns_roster); +} + +void QXmppRosterIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement itemElement = element. + firstChildElement("query"). + firstChildElement("item"); + while(!itemElement.isNull()) + { + QXmppRosterIq::Item item; + item.parse(itemElement); + m_items.append(item); + itemElement = itemElement.nextSiblingElement(); + } +} + +void QXmppRosterIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("query"); + writer->writeAttribute( "xmlns", ns_roster); + + for(int i = 0; i < m_items.count(); ++i) + m_items.at(i).toXml(writer); + writer->writeEndElement(); +} + +/// Returns the bareJid of the roster entry. +/// +/// \return bareJid as a QString +/// + +QString QXmppRosterIq::Item::bareJid() const +{ + return m_bareJid; +} + +/// Sets the bareJid of the roster entry. +/// +/// \param bareJid as a QString +/// + +void QXmppRosterIq::Item::setBareJid(const QString &bareJid) +{ + m_bareJid = bareJid; +} + +/// Returns the groups of the roster entry. +/// +/// \return QSet list of all the groups +/// + +QSet QXmppRosterIq::Item::groups() const +{ + return m_groups; +} + +/// Sets the groups of the roster entry. +/// +/// \param groups list of all the groups as a QSet +/// + +void QXmppRosterIq::Item::setGroups(const QSet& groups) +{ + m_groups = groups; +} + +/// Returns the name of the roster entry. +/// +/// \return name as a QString +/// + +QString QXmppRosterIq::Item::name() const +{ + return m_name; +} + +/// Sets the name of the roster entry. +/// +/// \param name as a QString +/// + +void QXmppRosterIq::Item::setName(const QString &name) +{ + m_name = name; +} + +/// Returns the subscription status of the roster entry. It is the "ask" +/// attribute in the Roster IQ stanza. Its value can be "subscribe" or "unsubscribe" +/// or empty. +/// +/// \return subscription status as a QString +/// +/// + +QString QXmppRosterIq::Item::subscriptionStatus() const +{ + return m_subscriptionStatus; +} + +/// Sets the subscription status of the roster entry. It is the "ask" +/// attribute in the Roster IQ stanza. Its value can be "subscribe" or "unsubscribe" +/// or empty. +/// +/// \param status as a QString +/// + +void QXmppRosterIq::Item::setSubscriptionStatus(const QString &status) +{ + m_subscriptionStatus = status; +} + +/// Returns the subscription type of the roster entry. +/// + +QXmppRosterIq::Item::SubscriptionType + QXmppRosterIq::Item::subscriptionType() const +{ + return m_type; +} + +/// Sets the subscription type of the roster entry. +/// +/// \param type +/// + +void QXmppRosterIq::Item::setSubscriptionType(SubscriptionType type) +{ + m_type = type; +} + +QString QXmppRosterIq::Item::getSubscriptionTypeStr() const +{ + switch(m_type) + { + case NotSet: + return ""; + case None: + return "none"; + case Both: + return "both"; + case From: + return "from"; + case To: + return "to"; + case Remove: + return "remove"; + default: + { + qWarning("QXmppRosterIq::Item::getTypeStr(): invalid type"); + return ""; + } + } +} + +void QXmppRosterIq::Item::setSubscriptionTypeFromStr(const QString& type) +{ + if(type == "") + setSubscriptionType(NotSet); + else if(type == "none") + setSubscriptionType(None); + else if(type == "both") + setSubscriptionType(Both); + else if(type == "from") + setSubscriptionType(From); + else if(type == "to") + setSubscriptionType(To); + else if(type == "remove") + setSubscriptionType(Remove); + else + qWarning("QXmppRosterIq::Item::setTypeFromStr(): invalid type"); +} + +void QXmppRosterIq::Item::parse(const QDomElement &element) +{ + m_name = element.attribute("name"); + m_bareJid = element.attribute("jid"); + setSubscriptionTypeFromStr(element.attribute("subscription")); + setSubscriptionStatus(element.attribute("ask")); + + QDomElement groupElement = element.firstChildElement("group"); + while(!groupElement.isNull()) + { + m_groups << groupElement.text(); + groupElement = groupElement.nextSiblingElement("group"); + } +} + +void QXmppRosterIq::Item::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("item"); + helperToXmlAddAttribute(writer,"jid", m_bareJid); + helperToXmlAddAttribute(writer,"name", m_name); + helperToXmlAddAttribute(writer,"subscription", getSubscriptionTypeStr()); + helperToXmlAddAttribute(writer, "ask", subscriptionStatus()); + + QSet::const_iterator i = m_groups.constBegin(); + while(i != m_groups.constEnd()) + { + helperToXmlAddTextElement(writer,"group", *i); + ++i; + } + writer->writeEndElement(); +} diff --git a/src/base/QXmppRosterIq.h b/src/base/QXmppRosterIq.h new file mode 100644 index 00000000..9680a176 --- /dev/null +++ b/src/base/QXmppRosterIq.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPROSTERIQ_H +#define QXMPPROSTERIQ_H + +#include "QXmppIq.h" +#include +#include + +/// \brief The QXmppRosterIq class represents a roster IQ. +/// +/// \ingroup Stanzas + +class QXmppRosterIq : public QXmppIq +{ +public: + + /// \brief The QXmppRosterIq::Item class represents a roster entry. + class Item + { + public: + /// An enumeration for type of subscription with the bareJid in the roster. + enum SubscriptionType + { + None = 0, ///< the user does not have a subscription to the + ///< contact's presence information, and the contact does + ///< not have a subscription to the user's presence information + From = 1, ///< the contact has a subscription to the user's presence information, + ///< but the user does not have a subscription to the contact's presence information + To = 2, ///< the user has a subscription to the contact's presence information, + ///< but the contact does not have a subscription to the user's presence information + Both = 3, ///< both the user and the contact have subscriptions to each + ///< other's presence information + Remove = 4, ///< to delete a roster item + NotSet = 8 ///< the subscription state was not specified + }; + + QString bareJid() const; + QSet groups() const; + QString name() const; + QString subscriptionStatus() const; + SubscriptionType subscriptionType() const; + + void setBareJid(const QString&); + void setGroups(const QSet&); + void setName(const QString&); + void setSubscriptionStatus(const QString&); + void setSubscriptionType(SubscriptionType); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + + private: + QString getSubscriptionTypeStr() const; + void setSubscriptionTypeFromStr(const QString&); + + QString m_bareJid; + SubscriptionType m_type; + QString m_name; + // can be subscribe/unsubscribe (attribute "ask") + QString m_subscriptionStatus; + QSet m_groups; + }; + + void addItem(const Item&); + QList items() const; + + /// \cond + static bool isRosterIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QList m_items; +}; + +#endif // QXMPPROSTERIQ_H diff --git a/src/base/QXmppRpcIq.cpp b/src/base/QXmppRpcIq.cpp new file mode 100644 index 00000000..a2647077 --- /dev/null +++ b/src/base/QXmppRpcIq.cpp @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Ian Reinhart Geiser + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +#include "QXmppConstants.h" +#include "QXmppRpcIq.h" +#include "QXmppUtils.h" + +void XMLRPC::marshall(QXmlStreamWriter *writer, const QVariant &value) +{ + writer->writeStartElement("value"); + switch( value.type() ) + { + case QVariant::Int: + case QVariant::UInt: + case QVariant::LongLong: + case QVariant::ULongLong: + writer->writeTextElement("i4", value.toString()); + break; + case QVariant::Double: + writer->writeTextElement("double", value.toString()); + break; + case QVariant::Bool: + writer->writeTextElement("boolean", value.toBool() ? "1" : "0"); + break; + case QVariant::Date: + writer->writeTextElement("dateTime.iso8601", value.toDate().toString( Qt::ISODate ) ); + break; + case QVariant::DateTime: + writer->writeTextElement("dateTime.iso8601", value.toDateTime().toString( Qt::ISODate ) ); + break; + case QVariant::Time: + writer->writeTextElement("dateTime.iso8601", value.toTime().toString( Qt::ISODate ) ); + break; + case QVariant::StringList: + case QVariant::List: + { + writer->writeStartElement("array"); + writer->writeStartElement("data"); + foreach(const QVariant &item, value.toList()) + marshall(writer, item); + writer->writeEndElement(); + writer->writeEndElement(); + break; + } + case QVariant::Map: + { + writer->writeStartElement("struct"); + QMap map = value.toMap(); + QMap::ConstIterator index = map.begin(); + while( index != map.end() ) + { + writer->writeStartElement("member"); + writer->writeTextElement("name", index.key()); + marshall( writer, *index ); + writer->writeEndElement(); + ++index; + } + writer->writeEndElement(); + break; + } + case QVariant::ByteArray: + { + writer->writeTextElement("base64", value.toByteArray().toBase64() ); + break; + } + default: + { + if (value.isNull()) + writer->writeEmptyElement("nil"); + else if( value.canConvert(QVariant::String) ) + { + writer->writeTextElement("string", value.toString() ); + } + break; + } + } + writer->writeEndElement(); +} + +QVariant XMLRPC::demarshall(const QDomElement &elem, QStringList &errors) +{ + if ( elem.tagName().toLower() != "value" ) + { + errors << "Bad param value"; + return QVariant(); + } + + if ( !elem.firstChild().isElement() ) + { + return QVariant( elem.text() ); + } + + const QDomElement typeData = elem.firstChild().toElement(); + const QString typeName = typeData.tagName().toLower(); + + if (typeName == "nil") + { + return QVariant(); + } + if ( typeName == "string" ) + { + return QVariant( typeData.text() ); + } + else if (typeName == "int" || typeName == "i4" ) + { + bool ok = false; + QVariant val( typeData.text().toInt( &ok ) ); + if (ok) + return val; + errors << "I was looking for an integer but data was courupt"; + return QVariant(); + } + else if( typeName == "double" ) + { + bool ok = false; + QVariant val( typeData.text().toDouble( &ok ) ); + if (ok) + return val; + errors << "I was looking for an double but data was corrupt"; + } + else if( typeName == "boolean" ) + return QVariant( typeData.text() == "1" || typeData.text().toLower() == "true" ); + else if( typeName == "datetime" || typeName == "datetime.iso8601" ) + return QVariant( QDateTime::fromString( typeData.text(), Qt::ISODate ) ); + else if( typeName == "array" ) + { + QVariantList arr; + QDomElement valueNode = typeData.firstChildElement("data").firstChildElement(); + while (!valueNode.isNull() && errors.isEmpty()) + { + arr.append(demarshall(valueNode, errors)); + valueNode = valueNode.nextSiblingElement(); + } + return QVariant( arr ); + } + else if( typeName == "struct" ) + { + QMap stct; + QDomNode valueNode = typeData.firstChild(); + while(!valueNode.isNull() && errors.isEmpty()) + { + const QDomElement memberNode = valueNode.toElement().elementsByTagName("name").item(0).toElement(); + const QDomElement dataNode = valueNode.toElement().elementsByTagName("value").item(0).toElement(); + stct[ memberNode.text() ] = demarshall(dataNode, errors); + valueNode = valueNode.nextSibling(); + } + return QVariant(stct); + } + else if( typeName == "base64" ) + { + QVariant returnVariant; + QByteArray dest; + QByteArray src = typeData.text().toLatin1(); + return QVariant(QByteArray::fromBase64(src)); + } + + errors << QString( "Cannot handle type %1").arg(typeName); + return QVariant(); +} + +QXmppRpcErrorIq::QXmppRpcErrorIq() : QXmppIq( QXmppIq::Error ) +{ + +} + +QXmppRpcInvokeIq QXmppRpcErrorIq::query() const +{ + return m_query; +} + +void QXmppRpcErrorIq::setQuery(const QXmppRpcInvokeIq &query) +{ + m_query = query; +} + +bool QXmppRpcErrorIq::isRpcErrorIq(const QDomElement &element) +{ + QString type = element.attribute("type"); + QDomElement errorElement = element.firstChildElement("error"); + QDomElement queryElement = element.firstChildElement("query"); + return (type == "error") && + !errorElement.isNull() && + queryElement.namespaceURI() == ns_rpc; +} + +void QXmppRpcErrorIq::parseElementFromChild(const QDomElement &element) +{ + m_query.parseElementFromChild(element); +} + +void QXmppRpcErrorIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + m_query.toXmlElementFromChild(writer); +} + +QXmppRpcResponseIq::QXmppRpcResponseIq() + : QXmppIq(QXmppIq::Result), + m_faultCode(0) +{ +} + +/// Returns the fault code. +/// + +int QXmppRpcResponseIq::faultCode() const +{ + return m_faultCode; +} + +/// Sets the fault code. +/// +/// \param faultCode + +void QXmppRpcResponseIq::setFaultCode(int faultCode) +{ + m_faultCode = faultCode; +} + +/// Returns the fault string. +/// + +QString QXmppRpcResponseIq::faultString() const +{ + return m_faultString; +} + +/// Sets the fault string. +/// +/// \param faultString + +void QXmppRpcResponseIq::setFaultString(const QString& faultString) +{ + m_faultString = faultString; +} + +/// Returns the response values. +/// + +QVariantList QXmppRpcResponseIq::values() const +{ + return m_values; +} + +/// Sets the response values. +/// +/// \param values + +void QXmppRpcResponseIq::setValues(const QVariantList &values) +{ + m_values = values; +} + +bool QXmppRpcResponseIq::isRpcResponseIq(const QDomElement &element) +{ + QString type = element.attribute("type"); + QDomElement dataElement = element.firstChildElement("query"); + return dataElement.namespaceURI() == ns_rpc && + type == "result"; +} + +void QXmppRpcResponseIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + QDomElement methodElement = queryElement.firstChildElement("methodResponse"); + + const QDomElement contents = methodElement.firstChildElement(); + if( contents.tagName().toLower() == "params") + { + QDomNode param = contents.firstChildElement("param"); + while (!param.isNull()) + { + QStringList errors; + const QVariant value = XMLRPC::demarshall(param.firstChildElement("value"), errors); + if (!errors.isEmpty()) + break; + m_values << value; + param = param.nextSiblingElement("param"); + } + } + else if( contents.tagName().toLower() == "fault") + { + QStringList errors; + const QDomElement errElement = contents.firstChildElement("value"); + const QVariant error = XMLRPC::demarshall(errElement, errors); + if (!errors.isEmpty()) + return; + m_faultCode = error.toMap()["faultCode"].toInt(); + m_faultString = error.toMap()["faultString"].toString(); + } +} + +void QXmppRpcResponseIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("query"); + writer->writeAttribute("xmlns", ns_rpc); + + writer->writeStartElement("methodResponse"); + if (m_faultCode) + { + writer->writeStartElement("fault"); + QMap fault; + fault["faultCode"] = m_faultCode; + fault["faultString"] = m_faultString; + XMLRPC::marshall(writer, fault); + writer->writeEndElement(); + } + else if (!m_values.isEmpty()) + { + writer->writeStartElement("params"); + foreach (const QVariant &arg, m_values) + { + writer->writeStartElement("param"); + XMLRPC::marshall(writer, arg); + writer->writeEndElement(); + } + writer->writeEndElement(); + } + writer->writeEndElement(); + + writer->writeEndElement(); +} + +QXmppRpcInvokeIq::QXmppRpcInvokeIq() + : QXmppIq(QXmppIq::Set) +{ +} + +/// Returns the method arguments. +/// + +QVariantList QXmppRpcInvokeIq::arguments() const +{ + return m_arguments; +} + +/// Sets the method arguments. +/// +/// \param arguments + +void QXmppRpcInvokeIq::setArguments(const QVariantList &arguments) +{ + m_arguments = arguments; +} + +/// Returns the method name. +/// + +QString QXmppRpcInvokeIq::method() const +{ + return m_method; +} + +/// Sets the method name. +/// +/// \param method + +void QXmppRpcInvokeIq::setMethod(const QString &method) +{ + m_method = method; +} + +bool QXmppRpcInvokeIq::isRpcInvokeIq(const QDomElement &element) +{ + QString type = element.attribute("type"); + QDomElement dataElement = element.firstChildElement("query"); + return dataElement.namespaceURI() == ns_rpc && + type == "set"; +} + +void QXmppRpcInvokeIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + QDomElement methodElement = queryElement.firstChildElement("methodCall"); + + m_method = methodElement.firstChildElement("methodName").text(); + + const QDomElement methodParams = methodElement.firstChildElement("params"); + m_arguments.clear(); + if( !methodParams.isNull() ) + { + QDomNode param = methodParams.firstChildElement("param"); + while (!param.isNull()) + { + QStringList errors; + QVariant arg = XMLRPC::demarshall(param.firstChildElement("value"), errors); + if (!errors.isEmpty()) + break; + m_arguments << arg; + param = param.nextSiblingElement("param"); + } + } +} + +void QXmppRpcInvokeIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("query"); + writer->writeAttribute("xmlns", ns_rpc); + + writer->writeStartElement("methodCall"); + writer->writeTextElement("methodName", m_method); + if (!m_arguments.isEmpty()) + { + writer->writeStartElement("params"); + foreach(const QVariant &arg, m_arguments) + { + writer->writeStartElement("param"); + XMLRPC::marshall(writer, arg); + writer->writeEndElement(); + } + writer->writeEndElement(); + } + writer->writeEndElement(); + + writer->writeEndElement(); +} + diff --git a/src/base/QXmppRpcIq.h b/src/base/QXmppRpcIq.h new file mode 100644 index 00000000..f557686a --- /dev/null +++ b/src/base/QXmppRpcIq.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Ian Reinhart Geiser + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPRPCIQ_H +#define QXMPPRPCIQ_H + +#include "QXmppIq.h" +#include + +class QXmlStreamWriter; +class QDomElement; + +namespace XMLRPC +{ + void marshall( QXmlStreamWriter *writer, const QVariant &value); + QVariant demarshall(const QDomElement &elem, QStringList &errors); +} + +/// \brief The QXmppRpcResponseIq class represents an IQ used to carry +/// an RPC response as specified by XEP-0009: Jabber-RPC. +/// +/// \ingroup Stanzas + +class QXmppRpcResponseIq : public QXmppIq +{ +public: + QXmppRpcResponseIq(); + + int faultCode() const; + void setFaultCode(int faultCode); + + QString faultString() const; + void setFaultString(const QString &faultString); + + QVariantList values() const; + void setValues(const QVariantList &values); + + /// \cond + static bool isRpcResponseIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + int m_faultCode; + QString m_faultString; + QVariantList m_values; +}; + +/// \brief The QXmppRpcInvokeIq class represents an IQ used to carry +/// an RPC invocation as specified by XEP-0009: Jabber-RPC. +/// +/// \ingroup Stanzas + +class QXmppRpcInvokeIq : public QXmppIq +{ +public: + QXmppRpcInvokeIq(); + + QString method() const; + void setMethod( const QString &method ); + + QVariantList arguments() const; + void setArguments(const QVariantList &arguments); + + /// \cond + static bool isRpcInvokeIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QVariantList m_arguments; + QString m_method; + + friend class QXmppRpcErrorIq; +}; + +class QXmppRpcErrorIq : public QXmppIq +{ +public: + QXmppRpcErrorIq(); + + QXmppRpcInvokeIq query() const; + void setQuery(const QXmppRpcInvokeIq &query); + + /// \cond + static bool isRpcErrorIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QXmppRpcInvokeIq m_query; +}; + +#endif // QXMPPRPCIQ_H diff --git a/src/base/QXmppRtpChannel.cpp b/src/base/QXmppRtpChannel.cpp new file mode 100644 index 00000000..df26bc30 --- /dev/null +++ b/src/base/QXmppRtpChannel.cpp @@ -0,0 +1,1042 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include +#include +#include + +#include "QXmppCodec.h" +#include "QXmppJingleIq.h" +#include "QXmppRtpChannel.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338327950288 +#endif + +//#define QXMPP_DEBUG_RTP +//#define QXMPP_DEBUG_RTP_BUFFER +#define SAMPLE_BYTES 2 + +const quint8 RTP_VERSION = 0x02; + +/// Parses an RTP packet. +/// +/// \param ba + +bool QXmppRtpPacket::decode(const QByteArray &ba) +{ + if (ba.isEmpty()) + return false; + + // fixed header + quint8 tmp; + QDataStream stream(ba); + stream >> tmp; + version = (tmp >> 6); + const quint8 cc = (tmp >> 1) & 0xf; + const int hlen = 12 + 4 * cc; + if (version != RTP_VERSION || ba.size() < hlen) + return false; + stream >> tmp; + marker = (tmp >> 7); + type = tmp & 0x7f; + stream >> sequence; + stream >> stamp; + stream >> ssrc; + + // contributing source IDs + csrc.clear(); + quint32 src; + for (int i = 0; i < cc; ++i) { + stream >> src; + csrc << src; + } + + // retrieve payload + payload = ba.right(ba.size() - hlen); + return true; +} + +/// Encodes an RTP packet. + +QByteArray QXmppRtpPacket::encode() const +{ + Q_ASSERT(csrc.size() < 16); + + // fixed header + QByteArray ba; + ba.resize(payload.size() + 12 + 4 * csrc.size()); + QDataStream stream(&ba, QIODevice::WriteOnly); + stream << quint8(((version & 0x3) << 6) | + ((csrc.size() & 0xf) << 1)); + stream << quint8((type & 0x7f) | (marker << 7)); + stream << sequence; + stream << stamp; + stream << ssrc; + + // contributing source ids + foreach (const quint32 &src, csrc) + stream << src; + + stream.writeRawData(payload.constData(), payload.size()); + return ba; +} + +/// Returns a string representation of the RTP header. + +QString QXmppRtpPacket::toString() const +{ + return QString("RTP packet seq %1 stamp %2 marker %3 type %4 size %5").arg( + QString::number(sequence), + QString::number(stamp), + QString::number(marker), + QString::number(type), + QString::number(payload.size())); +} + +/// Creates a new RTP channel. + +QXmppRtpChannel::QXmppRtpChannel() + : m_outgoingPayloadNumbered(false) +{ +} + +/// Returns the local payload types. +/// + +QList QXmppRtpChannel::localPayloadTypes() +{ + m_outgoingPayloadNumbered = true; + return m_outgoingPayloadTypes; +} + +/// Sets the remote payload types. +/// +/// \param remotePayloadTypes + +void QXmppRtpChannel::setRemotePayloadTypes(const QList &remotePayloadTypes) +{ + QList commonOutgoingTypes; + QList commonIncomingTypes; + + foreach (const QXmppJinglePayloadType &incomingType, remotePayloadTypes) { + // check we support this payload type + int outgoingIndex = m_outgoingPayloadTypes.indexOf(incomingType); + if (outgoingIndex < 0) + continue; + QXmppJinglePayloadType outgoingType = m_outgoingPayloadTypes[outgoingIndex]; + + // be kind and try to adopt the other agent's numbering + if (!m_outgoingPayloadNumbered && outgoingType.id() > 95) { + outgoingType.setId(incomingType.id()); + } + commonIncomingTypes << incomingType; + commonOutgoingTypes << outgoingType; + } + if (commonOutgoingTypes.isEmpty()) { + qWarning("QXmppRtpChannel could not negociate a common codec"); + return; + } + m_incomingPayloadTypes = commonIncomingTypes; + m_outgoingPayloadTypes = commonOutgoingTypes; + m_outgoingPayloadNumbered = true; + + // call hook + payloadTypesChanged(); +} + +void QXmppRtpChannel::payloadTypesChanged() +{ +} + +enum CodecId { + G711u = 0, + GSM = 3, + G723 = 4, + G711a = 8, + G722 = 9, + L16Stereo = 10, + L16Mono = 11, + G728 = 15, + G729 = 18, +}; + +struct ToneInfo +{ + QXmppRtpAudioChannel::Tone tone; + quint32 incomingStart; + quint32 outgoingStart; + bool finished; +}; + +static QPair toneFreqs(QXmppRtpAudioChannel::Tone tone) +{ + switch (tone) { + case QXmppRtpAudioChannel::Tone_1: return qMakePair(697, 1209); + case QXmppRtpAudioChannel::Tone_2: return qMakePair(697, 1336); + case QXmppRtpAudioChannel::Tone_3: return qMakePair(697, 1477); + case QXmppRtpAudioChannel::Tone_A: return qMakePair(697, 1633); + case QXmppRtpAudioChannel::Tone_4: return qMakePair(770, 1209); + case QXmppRtpAudioChannel::Tone_5: return qMakePair(770, 1336); + case QXmppRtpAudioChannel::Tone_6: return qMakePair(770, 1477); + case QXmppRtpAudioChannel::Tone_B: return qMakePair(770, 1633); + case QXmppRtpAudioChannel::Tone_7: return qMakePair(852, 1209); + case QXmppRtpAudioChannel::Tone_8: return qMakePair(852, 1336); + case QXmppRtpAudioChannel::Tone_9: return qMakePair(852, 1477); + case QXmppRtpAudioChannel::Tone_C: return qMakePair(852, 1633); + case QXmppRtpAudioChannel::Tone_Star: return qMakePair(941, 1209); + case QXmppRtpAudioChannel::Tone_0: return qMakePair(941, 1336); + case QXmppRtpAudioChannel::Tone_Pound: return qMakePair(941, 1477); + case QXmppRtpAudioChannel::Tone_D: return qMakePair(941, 1633); + } + return qMakePair(0, 0); +} + +QByteArray renderTone(QXmppRtpAudioChannel::Tone tone, int clockrate, quint32 clockTick, qint64 samples) +{ + QPair tf = toneFreqs(tone); + const float clockMult = 2.0 * M_PI / float(clockrate); + QByteArray chunk; + chunk.reserve(samples * SAMPLE_BYTES); + QDataStream output(&chunk, QIODevice::WriteOnly); + output.setByteOrder(QDataStream::LittleEndian); + for (quint32 i = 0; i < samples; ++i) { + quint16 val = 16383.0 * (sin(clockMult * clockTick * tf.first) + sin(clockMult * clockTick * tf.second)); + output << val; + clockTick++; + } + return chunk; +} + +class QXmppRtpAudioChannelPrivate +{ +public: + QXmppRtpAudioChannelPrivate(QXmppRtpAudioChannel *qq); + QXmppCodec *codecForPayloadType(const QXmppJinglePayloadType &payloadType); + + // signals + bool signalsEmitted; + qint64 writtenSinceLastEmit; + + // RTP + QHostAddress remoteHost; + quint16 remotePort; + + QByteArray incomingBuffer; + bool incomingBuffering; + QMap incomingCodecs; + int incomingMinimum; + int incomingMaximum; + // position of the head of the incoming buffer, in bytes + qint64 incomingPos; + quint16 incomingSequence; + + QByteArray outgoingBuffer; + quint16 outgoingChunk; + QXmppCodec *outgoingCodec; + bool outgoingMarker; + bool outgoingPayloadNumbered; + quint16 outgoingSequence; + quint32 outgoingStamp; + QTimer *outgoingTimer; + QList outgoingTones; + QXmppJinglePayloadType outgoingTonesType; + + quint32 outgoingSsrc; + QXmppJinglePayloadType payloadType; + +private: + QXmppRtpAudioChannel *q; +}; + +QXmppRtpAudioChannelPrivate::QXmppRtpAudioChannelPrivate(QXmppRtpAudioChannel *qq) + : signalsEmitted(false), + writtenSinceLastEmit(0), + incomingBuffering(true), + incomingMinimum(0), + incomingMaximum(0), + incomingPos(0), + incomingSequence(0), + outgoingCodec(0), + outgoingMarker(true), + outgoingPayloadNumbered(false), + outgoingSequence(1), + outgoingStamp(0), + outgoingSsrc(0), + q(qq) +{ + qRegisterMetaType("QXmppRtpAudioChannel::Tone"); + outgoingSsrc = qrand(); +} + +/// Returns the audio codec for the given payload type. +/// + +QXmppCodec *QXmppRtpAudioChannelPrivate::codecForPayloadType(const QXmppJinglePayloadType &payloadType) +{ + if (payloadType.id() == G711u) + return new QXmppG711uCodec(payloadType.clockrate()); + else if (payloadType.id() == G711a) + return new QXmppG711aCodec(payloadType.clockrate()); +#ifdef QXMPP_USE_SPEEX + else if (payloadType.name().toLower() == "speex") + return new QXmppSpeexCodec(payloadType.clockrate()); +#endif + return 0; +} + +/// Creates a new RTP audio channel. +/// +/// \param parent + +QXmppRtpAudioChannel::QXmppRtpAudioChannel(QObject *parent) + : QIODevice(parent) +{ + d = new QXmppRtpAudioChannelPrivate(this); + QXmppLoggable *logParent = qobject_cast(parent); + if (logParent) { + connect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), + logParent, SIGNAL(logMessage(QXmppLogger::MessageType,QString))); + } + d->outgoingTimer = new QTimer(this); + connect(d->outgoingTimer, SIGNAL(timeout()), this, SLOT(writeDatagram())); + + // set supported codecs + QXmppJinglePayloadType payload; + +#ifdef QXMPP_USE_SPEEX + payload.setId(96); + payload.setChannels(1); + payload.setName("speex"); + payload.setClockrate(8000); + m_outgoingPayloadTypes << payload; +#endif + + payload.setId(G711u); + payload.setChannels(1); + payload.setName("PCMU"); + payload.setClockrate(8000); + m_outgoingPayloadTypes << payload; + + payload.setId(G711a); + payload.setChannels(1); + payload.setName("PCMA"); + payload.setClockrate(8000); + m_outgoingPayloadTypes << payload; + + QMap parameters; + parameters.insert("events", "0-15"); + payload.setId(101); + payload.setChannels(1); + payload.setName("telephone-event"); + payload.setClockrate(8000); + payload.setParameters(parameters); + m_outgoingPayloadTypes << payload; +} + +/// Destroys an RTP audio channel. +/// + +QXmppRtpAudioChannel::~QXmppRtpAudioChannel() +{ + foreach (QXmppCodec *codec, d->incomingCodecs) + delete codec; + if (d->outgoingCodec) + delete d->outgoingCodec; + delete d; +} + +/// Returns the number of bytes that are available for reading. +/// + +qint64 QXmppRtpAudioChannel::bytesAvailable() const +{ + return d->incomingBuffer.size(); +} + +/// Closes the RTP channel. +/// + +void QXmppRtpAudioChannel::close() +{ + d->outgoingTimer->stop(); + QIODevice::close(); +} + +/// Processes an incoming RTP packet. +/// +/// \param ba + +void QXmppRtpAudioChannel::datagramReceived(const QByteArray &ba) +{ + QXmppRtpPacket packet; + if (!packet.decode(ba)) + return; + +#ifdef QXMPP_DEBUG_RTP + logReceived(packet.toString()); +#endif + + // check sequence number +#if 0 + if (d->incomingSequence && packet.sequence != d->incomingSequence + 1) + warning(QString("RTP packet seq %1 is out of order, previous was %2") + .arg(QString::number(packet.sequence)) + .arg(QString::number(d->incomingSequence))); +#endif + d->incomingSequence = packet.sequence; + + // get or create codec + QXmppCodec *codec = 0; + if (!d->incomingCodecs.contains(packet.type)) { + foreach (const QXmppJinglePayloadType &payload, m_incomingPayloadTypes) { + if (packet.type == payload.id()) { + codec = d->codecForPayloadType(payload); + break; + } + } + if (codec) + d->incomingCodecs.insert(packet.type, codec); + else + warning(QString("Could not find codec for RTP type %1").arg(QString::number(packet.type))); + } else { + codec = d->incomingCodecs.value(packet.type); + } + if (!codec) + return; + + // determine packet's position in the buffer (in bytes) + qint64 packetOffset = 0; + if (!d->incomingBuffer.isEmpty()) { + packetOffset = packet.stamp * SAMPLE_BYTES - d->incomingPos; + if (packetOffset < 0) { +#ifdef QXMPP_DEBUG_RTP_BUFFER + warning(QString("RTP packet stamp %1 is too old, buffer start is %2") + .arg(QString::number(packet.stamp)) + .arg(QString::number(d->incomingPos))); +#endif + return; + } + } else { + d->incomingPos = packet.stamp * SAMPLE_BYTES + (d->incomingPos % SAMPLE_BYTES); + } + + // allocate space for new packet + // FIXME: this is wrong, we want the decoded data size! + qint64 packetLength = packet.payload.size(); + if (packetOffset + packetLength > d->incomingBuffer.size()) + d->incomingBuffer += QByteArray(packetOffset + packetLength - d->incomingBuffer.size(), 0); + QDataStream input(packet.payload); + QDataStream output(&d->incomingBuffer, QIODevice::WriteOnly); + output.device()->seek(packetOffset); + output.setByteOrder(QDataStream::LittleEndian); + codec->decode(input, output); + + // check whether we are running late + if (d->incomingBuffer.size() > d->incomingMaximum) + { + qint64 droppedSize = d->incomingBuffer.size() - d->incomingMinimum; + const int remainder = droppedSize % SAMPLE_BYTES; + if (remainder) + droppedSize -= remainder; +#ifdef QXMPP_DEBUG_RTP_BUFFER + warning(QString("Incoming RTP buffer is too full, dropping %1 bytes") + .arg(QString::number(droppedSize))); +#endif + d->incomingBuffer.remove(0, droppedSize); + d->incomingPos += droppedSize; + } + // check whether we have filled the initial buffer + if (d->incomingBuffer.size() >= d->incomingMinimum) + d->incomingBuffering = false; + if (!d->incomingBuffering) + emit readyRead(); +} + +void QXmppRtpAudioChannel::emitSignals() +{ + emit bytesWritten(d->writtenSinceLastEmit); + d->writtenSinceLastEmit = 0; + d->signalsEmitted = false; +} + +/// Returns true, as the RTP channel is a sequential device. +/// + +bool QXmppRtpAudioChannel::isSequential() const +{ + return true; +} + +QIODevice::OpenMode QXmppRtpAudioChannel::openMode() const +{ + return QIODevice::openMode(); +} + +qint64 QXmppRtpAudioChannel::readData(char * data, qint64 maxSize) +{ + // if we are filling the buffer, return empty samples + if (d->incomingBuffering) + { + // FIXME: if we are asked for a non-integer number of samples, + // we will return junk on next read as we don't increment d->incomingPos + memset(data, 0, maxSize); + return maxSize; + } + + qint64 readSize = qMin(maxSize, qint64(d->incomingBuffer.size())); + memcpy(data, d->incomingBuffer.constData(), readSize); + d->incomingBuffer.remove(0, readSize); + if (readSize < maxSize) + { +#ifdef QXMPP_DEBUG_RTP + debug(QString("QXmppRtpAudioChannel::readData missing %1 bytes").arg(QString::number(maxSize - readSize))); +#endif + memset(data + readSize, 0, maxSize - readSize); + } + + // add local DTMF echo + if (!d->outgoingTones.isEmpty()) { + const int headOffset = d->incomingPos % SAMPLE_BYTES; + const int samples = (headOffset + maxSize + SAMPLE_BYTES - 1) / SAMPLE_BYTES; + const QByteArray chunk = renderTone( + d->outgoingTones[0].tone, + d->payloadType.clockrate(), + d->incomingPos / SAMPLE_BYTES - d->outgoingTones[0].incomingStart, + samples); + memcpy(data, chunk.constData() + headOffset, maxSize); + } + + d->incomingPos += maxSize; + return maxSize; +} + +/// Returns the RTP channel's payload type. +/// +/// You can use this to determine the QAudioFormat to use with your +/// QAudioInput/QAudioOutput. + +QXmppJinglePayloadType QXmppRtpAudioChannel::payloadType() const +{ + return d->payloadType; +} + +void QXmppRtpAudioChannel::payloadTypesChanged() +{ + // delete incoming codecs + foreach (QXmppCodec *codec, d->incomingCodecs) + delete codec; + d->incomingCodecs.clear(); + + // delete outgoing codec + if (d->outgoingCodec) { + delete d->outgoingCodec; + d->outgoingCodec = 0; + } + + // create outgoing codec + foreach (const QXmppJinglePayloadType &outgoingType, m_outgoingPayloadTypes) { + // check for telephony events + if (outgoingType.name() == "telephone-event") { + d->outgoingTonesType = outgoingType; + } + else if (!d->outgoingCodec) { + QXmppCodec *codec = d->codecForPayloadType(outgoingType); + if (codec) { + d->payloadType = outgoingType; + d->outgoingCodec = codec; + } + } + } + + // size in bytes of an decoded packet + d->outgoingChunk = SAMPLE_BYTES * d->payloadType.ptime() * d->payloadType.clockrate() / 1000; + d->outgoingTimer->setInterval(d->payloadType.ptime()); + + d->incomingMinimum = d->outgoingChunk * 5; + d->incomingMaximum = d->outgoingChunk * 15; + + open(QIODevice::ReadWrite | QIODevice::Unbuffered); +} + +/// Returns the position in the received audio data. + +qint64 QXmppRtpAudioChannel::pos() const +{ + return d->incomingPos; +} + +/// Seeks in the received audio data. +/// +/// Seeking backwards will result in empty samples being added at the start +/// of the buffer. +/// +/// \param pos + +bool QXmppRtpAudioChannel::seek(qint64 pos) +{ + qint64 delta = pos - d->incomingPos; + if (delta < 0) + d->incomingBuffer.prepend(QByteArray(-delta, 0)); + else + d->incomingBuffer.remove(0, delta); + d->incomingPos = pos; + return true; +} + +/// Starts sending the specified DTMF tone. +/// +/// \param tone + +void QXmppRtpAudioChannel::startTone(QXmppRtpAudioChannel::Tone tone) +{ + ToneInfo info; + info.tone = tone; + info.incomingStart = d->incomingPos / SAMPLE_BYTES; + info.outgoingStart = d->outgoingStamp; + info.finished = false; + d->outgoingTones << info; +} + +/// Stops sending the specified DTMF tone. +/// +/// \param tone + +void QXmppRtpAudioChannel::stopTone(QXmppRtpAudioChannel::Tone tone) +{ + for (int i = 0; i < d->outgoingTones.size(); ++i) { + if (d->outgoingTones[i].tone == tone) { + d->outgoingTones[i].finished = true; + break; + } + } +} + +qint64 QXmppRtpAudioChannel::writeData(const char * data, qint64 maxSize) +{ + if (!d->outgoingCodec) { + warning("QXmppRtpAudioChannel::writeData before codec was set"); + return -1; + } + + d->outgoingBuffer += QByteArray::fromRawData(data, maxSize); + + // start sending audio chunks + if (!d->outgoingTimer->isActive()) + d->outgoingTimer->start(); + + return maxSize; +} + +void QXmppRtpAudioChannel::writeDatagram() +{ + // read audio chunk + QByteArray chunk; + if (d->outgoingBuffer.size() < d->outgoingChunk) { +#ifdef QXMPP_DEBUG_RTP_BUFFER + warning("Outgoing RTP buffer is starved"); +#endif + chunk = QByteArray(d->outgoingChunk, 0); + } else { + chunk = d->outgoingBuffer.left(d->outgoingChunk); + d->outgoingBuffer.remove(0, d->outgoingChunk); + } + + bool sendAudio = true; + if (!d->outgoingTones.isEmpty()) { + const quint32 packetTicks = (d->payloadType.clockrate() * d->payloadType.ptime()) / 1000; + const ToneInfo info = d->outgoingTones[0]; + + if (d->outgoingTonesType.id()) { + // send RFC 2833 DTMF + QXmppRtpPacket packet; + packet.version = RTP_VERSION; + packet.marker = (info.outgoingStart == d->outgoingStamp); + packet.type = d->outgoingTonesType.id(); + packet.sequence = d->outgoingSequence; + packet.stamp = info.outgoingStart; + packet.ssrc = d->outgoingSsrc; + + QDataStream output(&packet.payload, QIODevice::WriteOnly); + output << quint8(info.tone); + output << quint8(info.finished ? 0x80 : 0x00); + output << quint16(d->outgoingStamp + packetTicks - info.outgoingStart); +#ifdef QXMPP_DEBUG_RTP + logSent(packet.toString()); +#endif + emit sendDatagram(packet.encode()); + d->outgoingSequence++; + d->outgoingStamp += packetTicks; + + sendAudio = false; + } else { + // generate in-band DTMF + chunk = renderTone(info.tone, d->payloadType.clockrate(), d->outgoingStamp - info.outgoingStart, packetTicks); + } + + // if the tone is finished, remove it + if (info.finished) + d->outgoingTones.removeFirst(); + } + + if (sendAudio) { + // send audio data + QXmppRtpPacket packet; + packet.version = RTP_VERSION; + if (d->outgoingMarker) + { + packet.marker = true; + d->outgoingMarker = false; + } else { + packet.marker = false; + } + packet.type = d->payloadType.id(); + packet.sequence = d->outgoingSequence; + packet.stamp = d->outgoingStamp; + packet.ssrc = d->outgoingSsrc; + + // encode audio chunk + QDataStream input(chunk); + input.setByteOrder(QDataStream::LittleEndian); + QDataStream output(&packet.payload, QIODevice::WriteOnly); + const qint64 packetTicks = d->outgoingCodec->encode(input, output); + +#ifdef QXMPP_DEBUG_RTP + logSent(packet.toString()); +#endif + emit sendDatagram(packet.encode()); + d->outgoingSequence++; + d->outgoingStamp += packetTicks; + } + + // queue signals + d->writtenSinceLastEmit += chunk.size(); + if (!d->signalsEmitted && !signalsBlocked()) { + d->signalsEmitted = true; + QMetaObject::invokeMethod(this, "emitSignals", Qt::QueuedConnection); + } +} + +/** Constructs a null video frame. + */ +QXmppVideoFrame::QXmppVideoFrame() + : m_bytesPerLine(0), + m_height(0), + m_mappedBytes(0), + m_pixelFormat(Format_Invalid), + m_width(0) +{ +} + +/** Constructs a video frame of the given pixel format and size in pixels. + * + * @param bytes + * @param size + * @param bytesPerLine + * @param format + */ +QXmppVideoFrame::QXmppVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format) + : m_bytesPerLine(bytesPerLine), + m_height(size.height()), + m_mappedBytes(bytes), + m_pixelFormat(format), + m_width(size.width()) +{ + m_data.resize(bytes); +} + +uchar *QXmppVideoFrame::bits() +{ + return (uchar*)m_data.data(); +} + +const uchar *QXmppVideoFrame::bits() const +{ + return (const uchar*)m_data.constData(); +} + +/** Returns the number of bytes in a scan line. + */ +int QXmppVideoFrame::bytesPerLine() const +{ + return m_bytesPerLine; +} + +/** Returns the height of a video frame. + */ +int QXmppVideoFrame::height() const +{ + return m_height; +} + +/** Returns true if the frame is valid. + */ +bool QXmppVideoFrame::isValid() const +{ + return m_pixelFormat != Format_Invalid && + m_height > 0 && m_width > 0 && + m_mappedBytes > 0; +} + +/** Returns the number of bytes occupied by the mapped frame data. + */ +int QXmppVideoFrame::mappedBytes() const +{ + return m_mappedBytes; +} + +/** Returns the color format of a video frame. + */ +QXmppVideoFrame::PixelFormat QXmppVideoFrame::pixelFormat() const +{ + return m_pixelFormat; +} + +/** Returns the size of a video frame. + */ +QSize QXmppVideoFrame::size() const +{ + return QSize(m_width, m_height); +} + +/** Returns the width of a video frame. + */ +int QXmppVideoFrame::width() const +{ + return m_width; +} + +class QXmppRtpVideoChannelPrivate +{ +public: + QXmppRtpVideoChannelPrivate(); + QMap decoders; + QXmppVideoEncoder *encoder; + QList frames; + + // local + QXmppVideoFormat outgoingFormat; + quint8 outgoingId; + quint16 outgoingSequence; + quint32 outgoingStamp; + quint32 outgoingSsrc; +}; + +QXmppRtpVideoChannelPrivate::QXmppRtpVideoChannelPrivate() + : encoder(0), + outgoingId(0), + outgoingSequence(1), + outgoingStamp(0), + outgoingSsrc(0) +{ + outgoingSsrc = qrand(); +} + +QXmppRtpVideoChannel::QXmppRtpVideoChannel(QObject *parent) + : QXmppLoggable(parent) +{ + d = new QXmppRtpVideoChannelPrivate; + d->outgoingFormat.setFrameRate(15.0); + d->outgoingFormat.setFrameSize(QSize(320, 240)); + d->outgoingFormat.setPixelFormat(QXmppVideoFrame::Format_YUYV); + + // set supported codecs + QXmppVideoEncoder *encoder; + QXmppJinglePayloadType payload; + Q_UNUSED(encoder); + Q_UNUSED(payload); + +#ifdef QXMPP_USE_VPX + encoder = new QXmppVpxEncoder; + encoder->setFormat(d->outgoingFormat); + payload.setId(96); + payload.setName("vp8"); + payload.setClockrate(90000); + payload.setParameters(encoder->parameters()); + m_outgoingPayloadTypes << payload; + delete encoder; +#endif + +#ifdef QXMPP_USE_THEORA + encoder = new QXmppTheoraEncoder; + encoder->setFormat(d->outgoingFormat); + payload.setId(97); + payload.setName("theora"); + payload.setClockrate(90000); + payload.setParameters(encoder->parameters()); + m_outgoingPayloadTypes << payload; + delete encoder; +#endif +} + +QXmppRtpVideoChannel::~QXmppRtpVideoChannel() +{ + foreach (QXmppVideoDecoder *decoder, d->decoders) + delete decoder; + if (d->encoder) + delete d->encoder; + delete d; +} + +/// Closes the RTP channel. +/// + +void QXmppRtpVideoChannel::close() +{ +} + +/// Processes an incoming RTP video packet. +/// +/// \param ba + +void QXmppRtpVideoChannel::datagramReceived(const QByteArray &ba) +{ + QXmppRtpPacket packet; + if (!packet.decode(ba)) + return; + +#ifdef QXMPP_DEBUG_RTP + logReceived(packet.toString()); +#endif + + // get codec + QXmppVideoDecoder *decoder = d->decoders.value(packet.type); + if (!decoder) + return; + d->frames << decoder->handlePacket(packet); +} + +QXmppVideoFormat QXmppRtpVideoChannel::decoderFormat() const +{ + if (d->decoders.isEmpty()) + return QXmppVideoFormat(); + const int key = d->decoders.keys().first(); + return d->decoders.value(key)->format(); +} + +QXmppVideoFormat QXmppRtpVideoChannel::encoderFormat() const +{ + return d->outgoingFormat; +} + +void QXmppRtpVideoChannel::setEncoderFormat(const QXmppVideoFormat &format) +{ + if (d->encoder && !d->encoder->setFormat(format)) + return; + d->outgoingFormat = format; +} + +QIODevice::OpenMode QXmppRtpVideoChannel::openMode() const +{ + QIODevice::OpenMode mode = QIODevice::NotOpen; + if (!d->decoders.isEmpty()) + mode |= QIODevice::ReadOnly; + if (d->encoder) + mode |= QIODevice::WriteOnly; + return mode; +} + +void QXmppRtpVideoChannel::payloadTypesChanged() +{ + // refresh decoders + foreach (QXmppVideoDecoder *decoder, d->decoders) + delete decoder; + d->decoders.clear(); + foreach (const QXmppJinglePayloadType &payload, m_incomingPayloadTypes) { + QXmppVideoDecoder *decoder = 0; + if (false) + {} +#ifdef QXMPP_USE_THEORA + else if (payload.name().toLower() == "theora") + decoder = new QXmppTheoraDecoder; +#endif +#ifdef QXMPP_USE_VPX + else if (payload.name().toLower() == "vp8") + decoder = new QXmppVpxDecoder; +#endif + if (decoder) { + decoder->setParameters(payload.parameters()); + d->decoders.insert(payload.id(), decoder); + } + } + + // refresh encoder + if (d->encoder) { + delete d->encoder; + d->encoder = 0; + } + foreach (const QXmppJinglePayloadType &payload, m_outgoingPayloadTypes) { + QXmppVideoEncoder *encoder = 0; + if (false) + {} +#ifdef QXMPP_USE_THEORA + else if (payload.name().toLower() == "theora") + encoder = new QXmppTheoraEncoder; +#endif +#ifdef QXMPP_USE_VPX + else if (payload.name().toLower() == "vp8") { + encoder = new QXmppVpxEncoder; + } +#endif + if (encoder) { + encoder->setFormat(d->outgoingFormat); + d->encoder = encoder; + d->outgoingId = payload.id(); + break; + } + } +} + +QList QXmppRtpVideoChannel::readFrames() +{ + const QList frames = d->frames; + d->frames.clear(); + return frames; +} + +void QXmppRtpVideoChannel::writeFrame(const QXmppVideoFrame &frame) +{ + if (!d->encoder) { + warning("QXmppRtpVideoChannel::writeFrame before codec was set"); + return; + } + + QXmppRtpPacket packet; + packet.version = RTP_VERSION; + packet.marker = false; + packet.type = d->outgoingId; + packet.ssrc = d->outgoingSsrc; + foreach (const QByteArray &payload, d->encoder->handleFrame(frame)) { + packet.sequence = d->outgoingSequence++; + packet.stamp = d->outgoingStamp; + packet.payload = payload; +#ifdef QXMPP_DEBUG_RTP + logSent(packet.toString()); +#endif + emit sendDatagram(packet.encode()); + } + d->outgoingStamp += 1; +} + diff --git a/src/base/QXmppRtpChannel.h b/src/base/QXmppRtpChannel.h new file mode 100644 index 00000000..0af6596c --- /dev/null +++ b/src/base/QXmppRtpChannel.h @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPRTPCHANNEL_H +#define QXMPPRTPCHANNEL_H + +#include +#include + +#include "QXmppJingleIq.h" +#include "QXmppLogger.h" + +class QXmppCodec; +class QXmppJinglePayloadType; +class QXmppRtpAudioChannelPrivate; +class QXmppRtpVideoChannelPrivate; + +/// \brief The QXmppRtpPacket class represents an RTP packet. +/// + +class QXmppRtpPacket +{ +public: + bool decode(const QByteArray &ba); + QByteArray encode() const; + QString toString() const; + + quint8 version; + bool marker; + quint8 type; + quint32 ssrc; + QList csrc; + quint16 sequence; + quint32 stamp; + QByteArray payload; +}; + +class QXmppRtpChannel +{ +public: + QXmppRtpChannel(); + + virtual void close() = 0; + virtual QIODevice::OpenMode openMode() const = 0; + QList localPayloadTypes(); + void setRemotePayloadTypes(const QList &remotePayloadTypes); + +protected: + virtual void payloadTypesChanged(); + + QList m_incomingPayloadTypes; + QList m_outgoingPayloadTypes; + bool m_outgoingPayloadNumbered; +}; + +/// \brief The QXmppRtpAudioChannel class represents an RTP audio channel to a remote party. +/// +/// It acts as a QIODevice so that you can read / write audio samples, for +/// instance using a QAudioOutput and a QAudioInput. +/// +/// \note THIS API IS NOT FINALIZED YET + +class QXmppRtpAudioChannel : public QIODevice, public QXmppRtpChannel +{ + Q_OBJECT + Q_ENUMS(Tone) + +public: + /// This enum is used to describe a DTMF tone. + enum Tone { + Tone_0 = 0, ///< Tone for the 0 key. + Tone_1, ///< Tone for the 1 key. + Tone_2, ///< Tone for the 2 key. + Tone_3, ///< Tone for the 3 key. + Tone_4, ///< Tone for the 4 key. + Tone_5, ///< Tone for the 5 key. + Tone_6, ///< Tone for the 6 key. + Tone_7, ///< Tone for the 7 key. + Tone_8, ///< Tone for the 8 key. + Tone_9, ///< Tone for the 9 key. + Tone_Star, ///< Tone for the * key. + Tone_Pound, ///< Tone for the # key. + Tone_A, ///< Tone for the A key. + Tone_B, ///< Tone for the B key. + Tone_C, ///< Tone for the C key. + Tone_D ///< Tone for the D key. + }; + + QXmppRtpAudioChannel(QObject *parent = 0); + ~QXmppRtpAudioChannel(); + + QXmppJinglePayloadType payloadType() const; + + /// \cond + qint64 bytesAvailable() const; + void close(); + bool isSequential() const; + QIODevice::OpenMode openMode() const; + qint64 pos() const; + bool seek(qint64 pos); + /// \endcond + +signals: + /// \brief This signal is emitted when a datagram needs to be sent. + void sendDatagram(const QByteArray &ba); + + /// \brief This signal is emitted to send logging messages. + void logMessage(QXmppLogger::MessageType type, const QString &msg); + +public slots: + void datagramReceived(const QByteArray &ba); + void startTone(QXmppRtpAudioChannel::Tone tone); + void stopTone(QXmppRtpAudioChannel::Tone tone); + +protected: + /// \cond + void debug(const QString &message) + { + emit logMessage(QXmppLogger::DebugMessage, qxmpp_loggable_trace(message)); + } + + void warning(const QString &message) + { + emit logMessage(QXmppLogger::WarningMessage, qxmpp_loggable_trace(message)); + } + + void logReceived(const QString &message) + { + emit logMessage(QXmppLogger::ReceivedMessage, qxmpp_loggable_trace(message)); + } + + void logSent(const QString &message) + { + emit logMessage(QXmppLogger::SentMessage, qxmpp_loggable_trace(message)); + } + + void payloadTypesChanged(); + qint64 readData(char * data, qint64 maxSize); + qint64 writeData(const char * data, qint64 maxSize); + /// \endcond + +private slots: + void emitSignals(); + void writeDatagram(); + +private: + friend class QXmppRtpAudioChannelPrivate; + QXmppRtpAudioChannelPrivate * d; +}; + +/// \brief The QXmppVideoFrame class provides a representation of a frame of video data. +/// +/// \note THIS API IS NOT FINALIZED YET + +class QXmppVideoFrame +{ +public: + enum PixelFormat { + Format_Invalid = 0, + Format_RGB32 = 3, + Format_RGB24 = 4, + Format_YUV420P = 18, + Format_UYVY = 20, + Format_YUYV = 21, + }; + + QXmppVideoFrame(); + QXmppVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format); + uchar *bits(); + const uchar *bits() const; + int bytesPerLine() const; + int height() const; + bool isValid() const; + int mappedBytes() const; + PixelFormat pixelFormat() const; + QSize size() const; + int width() const; + +private: + int m_bytesPerLine; + QByteArray m_data; + int m_height; + int m_mappedBytes; + PixelFormat m_pixelFormat; + int m_width; +}; + +class QXmppVideoFormat +{ +public: + int frameHeight() const { + return m_frameSize.height(); + } + + int frameWidth() const { + return m_frameSize.width(); + } + + qreal frameRate() const { + return m_frameRate; + } + + void setFrameRate(qreal frameRate) { + m_frameRate = frameRate; + } + + QSize frameSize() const { + return m_frameSize; + } + + void setFrameSize(const QSize &frameSize) { + m_frameSize = frameSize; + } + + QXmppVideoFrame::PixelFormat pixelFormat() const { + return m_pixelFormat; + } + + void setPixelFormat(QXmppVideoFrame::PixelFormat pixelFormat) { + m_pixelFormat = pixelFormat; + } + +private: + qreal m_frameRate; + QSize m_frameSize; + QXmppVideoFrame::PixelFormat m_pixelFormat; +}; + + +/// \brief The QXmppRtpVideoChannel class represents an RTP video channel to a remote party. +/// +/// \note THIS API IS NOT FINALIZED YET + +class QXmppRtpVideoChannel : public QXmppLoggable, public QXmppRtpChannel +{ + Q_OBJECT + +public: + QXmppRtpVideoChannel(QObject *parent = 0); + ~QXmppRtpVideoChannel(); + + // incoming stream + QXmppVideoFormat decoderFormat() const; + QList readFrames(); + + // outgoing stream + QXmppVideoFormat encoderFormat() const; + void setEncoderFormat(const QXmppVideoFormat &format); + void writeFrame(const QXmppVideoFrame &frame); + + QIODevice::OpenMode openMode() const; + void close(); + +signals: + /// \brief This signal is emitted when a datagram needs to be sent. + void sendDatagram(const QByteArray &ba); + +public slots: + void datagramReceived(const QByteArray &ba); + +protected: + void payloadTypesChanged(); + +private: + friend class QXmppRtpVideoChannelPrivate; + QXmppRtpVideoChannelPrivate * d; +}; + +#endif diff --git a/src/base/QXmppSaslAuth.cpp b/src/base/QXmppSaslAuth.cpp new file mode 100644 index 00000000..a528cd6d --- /dev/null +++ b/src/base/QXmppSaslAuth.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include + +#include "QXmppSaslAuth.h" +#include "QXmppUtils.h" + +QByteArray QXmppSaslDigestMd5::authzid() const +{ + return m_authzid; +} + +void QXmppSaslDigestMd5::setAuthzid(const QByteArray &authzid) +{ + m_authzid = authzid; +} + +QByteArray QXmppSaslDigestMd5::cnonce() const +{ + return m_cnonce; +} + +void QXmppSaslDigestMd5::setCnonce(const QByteArray &cnonce) +{ + m_cnonce = cnonce; +} + +QByteArray QXmppSaslDigestMd5::digestUri() const +{ + return m_digestUri; +} + +void QXmppSaslDigestMd5::setDigestUri(const QByteArray &digestUri) +{ + m_digestUri = digestUri; +} + +QByteArray QXmppSaslDigestMd5::nc() const +{ + return m_nc; +} + +void QXmppSaslDigestMd5::setNc(const QByteArray &nc) +{ + m_nc = nc; +} + +QByteArray QXmppSaslDigestMd5::nonce() const +{ + return m_nonce; +} + +void QXmppSaslDigestMd5::setNonce(const QByteArray &nonce) +{ + m_nonce = nonce; +} + +QByteArray QXmppSaslDigestMd5::qop() const +{ + return m_qop; +} + +void QXmppSaslDigestMd5::setQop(const QByteArray &qop) +{ + m_qop = qop; +} + +void QXmppSaslDigestMd5::setSecret(const QByteArray &secret) +{ + m_secret = secret; +} + +QByteArray QXmppSaslDigestMd5::generateNonce() +{ + QByteArray nonce = generateRandomBytes(32); + + // The random data can the '=' char is not valid as it is a delimiter, + // so to be safe, base64 the nonce + return nonce.toBase64(); +} + +/// Calculate digest response for use with XMPP/SASL. +/// +/// \param A2 +/// + +QByteArray QXmppSaslDigestMd5::calculateDigest(const QByteArray &A2) const +{ + QByteArray ha1 = m_secret + ':' + m_nonce + ':' + m_cnonce; + + if (!m_authzid.isEmpty()) + ha1 += ':' + m_authzid; + + return calculateDigest(ha1, A2); +} + +/// Calculate generic digest response. +/// +/// \param A1 +/// \param A2 +/// + +QByteArray QXmppSaslDigestMd5::calculateDigest(const QByteArray &A1, const QByteArray &A2) const +{ + QByteArray HA1 = QCryptographicHash::hash(A1, QCryptographicHash::Md5).toHex(); + QByteArray HA2 = QCryptographicHash::hash(A2, QCryptographicHash::Md5).toHex(); + QByteArray KD; + if (m_qop == "auth" || m_qop == "auth-int") + KD = HA1 + ':' + m_nonce + ':' + m_nc + ':' + m_cnonce + ':' + m_qop + ':' + HA2; + else + KD = HA1 + ':' + m_nonce + ':' + HA2; + return QCryptographicHash::hash(KD, QCryptographicHash::Md5).toHex(); +} + +QMap QXmppSaslDigestMd5::parseMessage(const QByteArray &ba) +{ + QMap map; + int startIndex = 0; + int pos = 0; + while ((pos = ba.indexOf("=", startIndex)) >= 0) + { + // key get name and skip equals + const QByteArray key = ba.mid(startIndex, pos - startIndex).trimmed(); + pos++; + + // check whether string is quoted + if (ba.at(pos) == '"') + { + // skip opening quote + pos++; + int endPos = ba.indexOf('"', pos); + // skip quoted quotes + while (endPos >= 0 && ba.at(endPos - 1) == '\\') + endPos = ba.indexOf('"', endPos + 1); + if (endPos < 0) + { + qWarning("Unfinished quoted string"); + return map; + } + // unquote + QByteArray value = ba.mid(pos, endPos - pos); + value.replace("\\\"", "\""); + value.replace("\\\\", "\\"); + map[key] = value; + // skip closing quote and comma + startIndex = endPos + 2; + } else { + // non-quoted string + int endPos = ba.indexOf(',', pos); + if (endPos < 0) + endPos = ba.size(); + map[key] = ba.mid(pos, endPos - pos); + // skip comma + startIndex = endPos + 1; + } + } + return map; +} + +QByteArray QXmppSaslDigestMd5::serializeMessage(const QMap &map) +{ + QByteArray ba; + foreach (const QByteArray &key, map.keys()) + { + if (!ba.isEmpty()) + ba.append(','); + ba.append(key + "="); + QByteArray value = map[key]; + const char *separators = "()<>@,;:\\\"/[]?={} \t"; + bool quote = false; + for (const char *c = separators; *c; c++) + { + if (value.contains(*c)) + { + quote = true; + break; + } + } + if (quote) + { + value.replace("\\", "\\\\"); + value.replace("\"", "\\\""); + ba.append("\"" + value + "\""); + } + else + ba.append(value); + } + return ba; +} + diff --git a/src/base/QXmppSaslAuth.h b/src/base/QXmppSaslAuth.h new file mode 100644 index 00000000..409636cb --- /dev/null +++ b/src/base/QXmppSaslAuth.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPSASLAUTH_H +#define QXMPPSASLAUTH_H + +#include +#include + +class QXmppSaslDigestMd5 +{ +public: + QByteArray authzid() const; + void setAuthzid(const QByteArray &cnonce); + + QByteArray cnonce() const; + void setCnonce(const QByteArray &cnonce); + + QByteArray digestUri() const; + void setDigestUri(const QByteArray &digestUri); + + QByteArray nc() const; + void setNc(const QByteArray &nc); + + QByteArray nonce() const; + void setNonce(const QByteArray &nonce); + + QByteArray qop() const; + void setQop(const QByteArray &qop); + + void setSecret(const QByteArray &secret); + + QByteArray calculateDigest(const QByteArray &A2) const; + QByteArray calculateDigest(const QByteArray &A1, const QByteArray &A2) const; + static QByteArray generateNonce(); + + // message parsing and serialization + static QMap parseMessage(const QByteArray &ba); + static QByteArray serializeMessage(const QMap &map); + +private: + QByteArray m_authzid; + QByteArray m_cnonce; + QByteArray m_digestUri; + QByteArray m_nc; + QByteArray m_nonce; + QByteArray m_qop; + QByteArray m_secret; +}; + +#endif diff --git a/src/base/QXmppSessionIq.cpp b/src/base/QXmppSessionIq.cpp new file mode 100644 index 00000000..6672cc0e --- /dev/null +++ b/src/base/QXmppSessionIq.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include +#include + +#include "QXmppSessionIq.h" +#include "QXmppConstants.h" +#include "QXmppUtils.h" + +bool QXmppSessionIq::isSessionIq(const QDomElement &element) +{ + QDomElement sessionElement = element.firstChildElement("session"); + return (sessionElement.namespaceURI() == ns_session); +} + +void QXmppSessionIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("session");; + writer->writeAttribute("xmlns", ns_session); + writer->writeEndElement(); +} + diff --git a/src/base/QXmppSessionIq.h b/src/base/QXmppSessionIq.h new file mode 100644 index 00000000..2cbcd58c --- /dev/null +++ b/src/base/QXmppSessionIq.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPSESSIONIQ_H +#define QXMPPSESSIONIQ_H + +#include "QXmppIq.h" + +/// \brief The QXmppSessionIq class represents an IQ used for session +/// establishment as defined by RFC 5921. +/// +/// \ingroup Stanzas + +class QXmppSessionIq : public QXmppIq +{ +public: + /// \cond + static bool isSessionIq(const QDomElement &element); + /// \endcond + +private: + /// \cond + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond +}; + +#endif // QXMPPSESSION_H diff --git a/src/base/QXmppSocks.cpp b/src/base/QXmppSocks.cpp new file mode 100644 index 00000000..1c6f162c --- /dev/null +++ b/src/base/QXmppSocks.cpp @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +#include "QXmppSocks.h" + +const static char SocksVersion = 5; + +enum AuthenticationMethod { + NoAuthentication = 0, + GSSAPI = 1, + UsernamePassword = 2, +}; + +enum Command { + ConnectCommand = 1, + BindCommand = 2, + AssociateCommand = 3, +}; + +enum AddressType { + IPv4Address = 1, + DomainName = 3, + IPv6Address = 4, +}; + +enum ReplyType { + Succeeded = 0, + SocksFailure = 1, + ConnectionNotAllowed = 2, + NetworkUnreachable = 3, + HostUnreachable = 4, + ConnectionRefused = 5, + TtlExpired = 6, + CommandNotSupported = 7, + AddressTypeNotSupported = 8, +}; + +enum State { + ConnectState = 0, + CommandState = 1, + ReadyState = 2, +}; + +static QByteArray encodeHostAndPort(quint8 type, const QByteArray &host, quint16 port) +{ + QByteArray buffer; + QDataStream stream(&buffer, QIODevice::WriteOnly); + // set host name + quint8 hostLength = host.size(); + stream << type; + stream << hostLength; + stream.writeRawData(host.constData(), hostLength); + // set port + stream << port; + return buffer; +} + +static bool parseHostAndPort(const QByteArray buffer, quint8 &type, QByteArray &host, quint16 &port) +{ + if (buffer.size() < 4) + return false; + + QDataStream stream(buffer); + // get host name + quint8 hostLength; + stream >> type; + stream >> hostLength; + if (buffer.size() < hostLength + 4) + { + qWarning("Invalid host length"); + return false; + } + host.resize(hostLength); + stream.readRawData(host.data(), hostLength); + // get port + stream >> port; + return true; +} + +QXmppSocksClient::QXmppSocksClient(const QHostAddress &proxyAddress, quint16 proxyPort, QObject *parent) + : QTcpSocket(parent), + m_proxyAddress(proxyAddress), + m_proxyPort(proxyPort), + m_step(ConnectState) +{ + connect(this, SIGNAL(connected()), this, SLOT(slotConnected())); + connect(this, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); +} + +void QXmppSocksClient::connectToHost(const QString &hostName, quint16 hostPort) +{ + m_hostName = hostName; + m_hostPort = hostPort; + QTcpSocket::connectToHost(m_proxyAddress, m_proxyPort); +} + +void QXmppSocksClient::slotConnected() +{ + m_step = ConnectState; + + // disconnect from signal + disconnect(this, SIGNAL(connected()), this, SLOT(slotConnected())); + + // send connect to server + QByteArray buffer; + buffer.resize(3); + buffer[0] = SocksVersion; + buffer[1] = 0x01; // number of methods + buffer[2] = NoAuthentication; + write(buffer); +} + +void QXmppSocksClient::slotReadyRead() +{ + if (m_step == ConnectState) + { + m_step++; + + // receive connect to server response + QByteArray buffer = readAll(); + if (buffer.size() != 2 || buffer.at(0) != SocksVersion || buffer.at(1) != NoAuthentication) + { + qWarning("QXmppSocksClient received an invalid response during handshake"); + close(); + return; + } + + // send CONNECT command + buffer.resize(3); + buffer[0] = SocksVersion; + buffer[1] = ConnectCommand; + buffer[2] = 0x00; // reserved + buffer.append(encodeHostAndPort( + DomainName, + m_hostName.toAscii(), + m_hostPort)); + write(buffer); + + } else if (m_step == CommandState) { + m_step++; + + // disconnect from signal + disconnect(this, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); + + // receive CONNECT response + QByteArray buffer = readAll(); + if (buffer.size() < 6 || + buffer.at(0) != SocksVersion || + buffer.at(1) != Succeeded || + buffer.at(2) != 0) + { + qWarning("QXmppSocksClient received an invalid response to CONNECT command"); + close(); + return; + } + + // parse host + quint8 hostType; + QByteArray hostName; + quint16 hostPort; + if (!parseHostAndPort(buffer.mid(3), hostType, hostName, hostPort)) + { + qWarning("QXmppSocksClient could not parse type/host/port"); + close(); + return; + } + // FIXME : what do we do with the resulting name / port? + + // notify of connection + emit ready(); + } +} + +bool QXmppSocksClient::waitForReady(int msecs) +{ + QEventLoop loop; + connect(this, SIGNAL(disconnected()), &loop, SLOT(quit())); + connect(this, SIGNAL(ready()), &loop, SLOT(quit())); + QTimer::singleShot(msecs, &loop, SLOT(quit())); + loop.exec(); + + if (m_step == ReadyState && isValid()) + return true; + else + return false; +} + +QXmppSocksServer::QXmppSocksServer(QObject *parent) + : QObject(parent) +{ + m_server = new QTcpServer(this); + connect(m_server, SIGNAL(newConnection()), this, SLOT(slotNewConnection())); +} + +void QXmppSocksServer::close() +{ + m_server->close(); +} + +bool QXmppSocksServer::listen(const QHostAddress &address, quint16 port) +{ + return m_server->listen(address, port); +} + +bool QXmppSocksServer::isListening() const +{ + return m_server->isListening(); +} + +QHostAddress QXmppSocksServer::serverAddress() const +{ + return m_server->serverAddress(); +} + +quint16 QXmppSocksServer::serverPort() const +{ + return m_server->serverPort(); +} + +void QXmppSocksServer::slotNewConnection() +{ + QTcpSocket *socket = m_server->nextPendingConnection(); + if (!socket) + return; + + // register socket + m_states.insert(socket, ConnectState); + connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); +} + +void QXmppSocksServer::slotReadyRead() +{ + QTcpSocket *socket = qobject_cast(sender()); + if (!socket || !m_states.contains(socket)) + return; + + if (m_states.value(socket) == ConnectState) + { + m_states.insert(socket, CommandState); + + // receive connect to server request + QByteArray buffer = socket->readAll(); + if (buffer.size() < 3 || + buffer.at(0) != SocksVersion || + buffer.at(1) + 2 != buffer.size()) + { + qWarning("QXmppSocksServer received invalid handshake"); + socket->close(); + return; + } + + // check authentication method + bool foundMethod = false; + for (int i = 2; i < buffer.size(); i++) + { + if (buffer.at(i) == NoAuthentication) + { + foundMethod = true; + break; + } + } + if (!foundMethod) + { + qWarning("QXmppSocksServer received bad authentication method"); + socket->close(); + return; + } + + // send connect to server response + buffer.resize(2); + buffer[0] = SocksVersion; + buffer[1] = NoAuthentication; + socket->write(buffer); + + } else if (m_states.value(socket) == CommandState) { + m_states.insert(socket, ReadyState); + + // disconnect from signals + disconnect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); + + // receive command + QByteArray buffer = socket->readAll(); + if (buffer.size() < 4 || + buffer.at(0) != SocksVersion || + buffer.at(1) != ConnectCommand || + buffer.at(2) != 0x00) + { + qWarning("QXmppSocksServer received an invalid command"); + socket->close(); + return; + } + + // parse host + quint8 hostType; + QByteArray hostName; + quint16 hostPort; + if (!parseHostAndPort(buffer.mid(3), hostType, hostName, hostPort)) + { + qWarning("QXmppSocksServer could not parse type/host/port"); + socket->close(); + return; + } + + // notify of connection + emit newConnection(socket, hostName, hostPort); + + // send response + buffer.resize(3); + buffer[0] = SocksVersion; + buffer[1] = Succeeded; + buffer[2] = 0x00; + buffer.append(encodeHostAndPort( + DomainName, + hostName, + hostPort)); + socket->write(buffer); + } +} + diff --git a/src/base/QXmppSocks.h b/src/base/QXmppSocks.h new file mode 100644 index 00000000..111055fe --- /dev/null +++ b/src/base/QXmppSocks.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPSOCKS_H +#define QXMPPSOCKS_H + +#include +#include + +class QTcpServer; + +class QXmppSocksClient : public QTcpSocket +{ + Q_OBJECT + +public: + QXmppSocksClient(const QHostAddress &proxyAddress, quint16 proxyPort, QObject *parent=0); + void connectToHost(const QString &hostName, quint16 hostPort); + bool waitForReady(int msecs = 30000); + +signals: + void ready(); + +private slots: + void slotConnected(); + void slotReadyRead(); + +private: + QHostAddress m_proxyAddress; + quint16 m_proxyPort; + QString m_hostName; + quint16 m_hostPort; + int m_step; +}; + +class QXmppSocksServer : public QObject +{ + Q_OBJECT + +public: + QXmppSocksServer(QObject *parent=0); + void close(); + bool isListening() const; + bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0); + + QHostAddress serverAddress() const; + quint16 serverPort() const; + +signals: + void newConnection(QTcpSocket *socket, QString hostName, quint16 port); + +private slots: + void slotNewConnection(); + void slotReadyRead(); + +private: + QTcpServer *m_server; + QMap m_states; +}; + +#endif diff --git a/src/base/QXmppStanza.cpp b/src/base/QXmppStanza.cpp new file mode 100644 index 00000000..e8937b6f --- /dev/null +++ b/src/base/QXmppStanza.cpp @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#include "QXmppStanza.h" +#include "QXmppUtils.h" +#include "QXmppConstants.h" + +#include +#include + +uint QXmppStanza::s_uniqeIdNo = 0; + +QXmppStanza::Error::Error(): + m_code(0), + m_type(static_cast(-1)), + m_condition(static_cast(-1)) +{ +} + +QXmppStanza::Error::Error(Type type, Condition cond, const QString& text): + m_code(0), + m_type(type), + m_condition(cond), + m_text(text) +{ +} + +QXmppStanza::Error::Error(const QString& type, const QString& cond, + const QString& text): + m_code(0), + m_text(text) +{ + setTypeFromStr(type); + setConditionFromStr(cond); +} + +QString QXmppStanza::Error::text() const +{ + return m_text; +} + +void QXmppStanza::Error::setText(const QString& text) +{ + m_text = text; +} + +int QXmppStanza::Error::code() const +{ + return m_code; +} + +void QXmppStanza::Error::setCode(int code) +{ + m_code = code; +} + +QXmppStanza::Error::Condition QXmppStanza::Error::condition() const +{ + return m_condition; +} + +void QXmppStanza::Error::setCondition(QXmppStanza::Error::Condition cond) +{ + m_condition = cond; +} + +QXmppStanza::Error::Type QXmppStanza::Error::type() const +{ + return m_type; +} + +void QXmppStanza::Error::setType(QXmppStanza::Error::Type type) +{ + m_type = type; +} + +QString QXmppStanza::Error::getTypeStr() const +{ + switch(m_type) + { + case Cancel: + return "cancel"; + case Continue: + return "continue"; + case Modify: + return "modify"; + case Auth: + return "auth"; + case Wait: + return "wait"; + default: + return ""; + } +} + +QString QXmppStanza::Error::getConditionStr() const +{ + switch(m_condition) + { + case BadRequest: + return "bad-request"; + case Conflict: + return "conflict"; + case FeatureNotImplemented: + return "feature-not-implemented"; + case Forbidden: + return "forbidden"; + case Gone: + return "gone"; + case InternalServerError: + return "internal-server-error"; + case ItemNotFound: + return "item-not-found"; + case JidMalformed: + return "jid-malformed"; + case NotAcceptable: + return "not-acceptable"; + case NotAllowed: + return "not-allowed"; + case NotAuthorized: + return "not-authorized"; + case PaymentRequired: + return "payment-required"; + case RecipientUnavailable: + return "recipient-unavailable"; + case Redirect: + return "redirect"; + case RegistrationRequired: + return "registration-required"; + case RemoteServerNotFound: + return "remote-server-not-found"; + case RemoteServerTimeout: + return "remote-server-timeout"; + case ResourceConstraint: + return "resource-constraint"; + case ServiceUnavailable: + return "service-unavailable"; + case SubscriptionRequired: + return "subscription-required"; + case UndefinedCondition: + return "undefined-condition"; + case UnexpectedRequest: + return "unexpected-request"; + default: + return ""; + } +} + +void QXmppStanza::Error::setTypeFromStr(const QString& type) +{ + if(type == "cancel") + setType(Cancel); + else if(type == "continue") + setType(Continue); + else if(type == "modify") + setType(Modify); + else if(type == "auth") + setType(Auth); + else if(type == "wait") + setType(Wait); + else + setType(static_cast(-1)); +} + +void QXmppStanza::Error::setConditionFromStr(const QString& type) +{ + if(type == "bad-request") + setCondition(BadRequest); + else if(type == "conflict") + setCondition(Conflict); + else if(type == "feature-not-implemented") + setCondition(FeatureNotImplemented); + else if(type == "forbidden") + setCondition(Forbidden); + else if(type == "gone") + setCondition(Gone); + else if(type == "internal-server-error") + setCondition(InternalServerError); + else if(type == "item-not-found") + setCondition(ItemNotFound); + else if(type == "jid-malformed") + setCondition(JidMalformed); + else if(type == "not-acceptable") + setCondition(NotAcceptable); + else if(type == "not-allowed") + setCondition(NotAllowed); + else if(type == "not-authorized") + setCondition(NotAuthorized); + else if(type == "payment-required") + setCondition(PaymentRequired); + else if(type == "recipient-unavailable") + setCondition(RecipientUnavailable); + else if(type == "redirect") + setCondition(Redirect); + else if(type == "registration-required") + setCondition(RegistrationRequired); + else if(type == "remote-server-not-found") + setCondition(RemoteServerNotFound); + else if(type == "remote-server-timeout") + setCondition(RemoteServerTimeout); + else if(type == "resource-constraint") + setCondition(ResourceConstraint); + else if(type == "service-unavailable") + setCondition(ServiceUnavailable); + else if(type == "subscription-required") + setCondition(SubscriptionRequired); + else if(type == "undefined-condition") + setCondition(UndefinedCondition); + else if(type == "unexpected-request") + setCondition(UnexpectedRequest); + else + setCondition(static_cast(-1)); +} + +bool QXmppStanza::Error::isValid() const +{ + return !(getTypeStr().isEmpty() && getConditionStr().isEmpty()); +} + +void QXmppStanza::Error::parse(const QDomElement &errorElement) +{ + setCode(errorElement.attribute("code").toInt()); + setTypeFromStr(errorElement.attribute("type")); + + QString text; + QString cond; + QDomElement element = errorElement.firstChildElement(); + while(!element.isNull()) + { + if(element.tagName() == "text") + text = element.text(); + else if(element.namespaceURI() == ns_stanza) + { + cond = element.tagName(); + } + element = element.nextSiblingElement(); + } + + setConditionFromStr(cond); + setText(text); +} + +void QXmppStanza::Error::toXml( QXmlStreamWriter *writer ) const +{ + QString cond = getConditionStr(); + QString type = getTypeStr(); + + if(cond.isEmpty() && type.isEmpty()) + return; + + writer->writeStartElement("error"); + helperToXmlAddAttribute(writer, "type", type); + + if (m_code > 0) + helperToXmlAddAttribute(writer, "code", QString::number(m_code)); + + if(!cond.isEmpty()) + { + writer->writeStartElement(cond); + writer->writeAttribute("xmlns", ns_stanza); + writer->writeEndElement(); + } + if(!m_text.isEmpty()) + { + writer->writeStartElement("text"); + writer->writeAttribute("xml:lang", "en"); + writer->writeAttribute("xmlns", ns_stanza); + writer->writeCharacters(m_text); + writer->writeEndElement(); + } + + writer->writeEndElement(); +} + +/// Constructs a QXmppStanza with the specified sender and recipient. +/// +/// \param from +/// \param to + +QXmppStanza::QXmppStanza(const QString& from, const QString& to) + : QXmppPacket(), + m_to(to), + m_from(from) +{ +} + +/// Destroys a QXmppStanza. + +QXmppStanza::~QXmppStanza() +{ +} + +/// Returns the stanza's recipient JID. +/// + +QString QXmppStanza::to() const +{ + return m_to; +} + +/// Sets the stanza's recipient JID. +/// +/// \param to + +void QXmppStanza::setTo(const QString& to) +{ + m_to = to; +} + +/// Returns the stanza's sender JID. + +QString QXmppStanza::from() const +{ + return m_from; +} + +/// Sets the stanza's sender JID. +/// +/// \param from + +void QXmppStanza::setFrom(const QString& from) +{ + m_from = from; +} + +/// Returns the stanza's identifier. + +QString QXmppStanza::id() const +{ + return m_id; +} + +/// Sets the stanza's identifier. +/// +/// \param id + +void QXmppStanza::setId(const QString& id) +{ + m_id = id; +} + +/// Returns the stanza's language. + +QString QXmppStanza::lang() const +{ + return m_lang; +} + +/// Sets the stanza's language. +/// +/// \param lang + +void QXmppStanza::setLang(const QString& lang) +{ + m_lang = lang; +} + +/// Returns the stanza's error. + +QXmppStanza::Error QXmppStanza::error() const +{ + return m_error; +} + +/// Sets the stanza's error. +/// +/// \param error + +void QXmppStanza::setError(const QXmppStanza::Error& error) +{ + m_error = error; +} + +/// Returns the stanza's "extensions". +/// +/// Extensions are XML elements which are not handled internally by QXmpp. + +QXmppElementList QXmppStanza::extensions() const +{ + return m_extensions; +} + +/// Sets the stanza's "extensions". +/// +/// \param extensions + +void QXmppStanza::setExtensions(const QXmppElementList &extensions) +{ + m_extensions = extensions; +} + +void QXmppStanza::generateAndSetNextId() +{ + // get back + ++s_uniqeIdNo; + m_id = "qxmpp" + QString::number(s_uniqeIdNo); +} + +bool QXmppStanza::isErrorStanza() const +{ + return m_error.isValid(); +} + +void QXmppStanza::parse(const QDomElement &element) +{ + m_from = element.attribute("from"); + m_to = element.attribute("to"); + m_id = element.attribute("id"); + m_lang = element.attribute("lang"); + + QDomElement errorElement = element.firstChildElement("error"); + if(!errorElement.isNull()) + m_error.parse(errorElement); +} + diff --git a/src/base/QXmppStanza.h b/src/base/QXmppStanza.h new file mode 100644 index 00000000..dc1c1346 --- /dev/null +++ b/src/base/QXmppStanza.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPSTANZA_H +#define QXMPPSTANZA_H + +#include "QXmppElement.h" +#include "QXmppPacket.h" +#include + +// forward declarations of QXmlStream* classes will not work on Mac, we need to +// include the whole header. +// See http://lists.trolltech.com/qt-interest/2008-07/thread00798-0.html +// for an explanation. +#include + +/// \defgroup Stanzas + +/// \brief The QXmppStanza class is the base class for all XMPP stanzas. +/// +/// \ingroup Stanzas + +class QXmppStanza : public QXmppPacket +{ +public: + class Error + { + public: + enum Type + { + Cancel, + Continue, + Modify, + Auth, + Wait + }; + + enum Condition + { + BadRequest, + Conflict, + FeatureNotImplemented, + Forbidden, + Gone, + InternalServerError, + ItemNotFound, + JidMalformed, + NotAcceptable, + NotAllowed, + NotAuthorized, + PaymentRequired, + RecipientUnavailable, + Redirect, + RegistrationRequired, + RemoteServerNotFound, + RemoteServerTimeout, + ResourceConstraint, + ServiceUnavailable, + SubscriptionRequired, + UndefinedCondition, + UnexpectedRequest + }; + + Error(); + Error(Type type, Condition cond, const QString& text=""); + Error(const QString& type, const QString& cond, const QString& text=""); + + int code() const; + void setCode(int code); + + QString text() const; + void setText(const QString& text); + + Condition condition() const; + void setCondition(Condition cond); + + void setType(Type type); + Type type() const; + + // FIXME : remove this once is gone + bool isValid() const; + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + + private: + QString getConditionStr() const; + void setConditionFromStr(const QString& cond); + + QString getTypeStr() const; + void setTypeFromStr(const QString& type); + + int m_code; + Type m_type; + Condition m_condition; + QString m_text; + }; + + QXmppStanza(const QString& from = QString(), const QString& to = QString()); + ~QXmppStanza(); + + QString to() const; + void setTo(const QString&); + + QString from() const; + void setFrom(const QString&); + + QString id() const; + void setId(const QString&); + + QString lang() const; + void setLang(const QString&); + + QXmppStanza::Error error() const; + void setError(const QXmppStanza::Error& error); + + QXmppElementList extensions() const; + void setExtensions(const QXmppElementList &elements); + + /// \cond + // FIXME : why is this needed? + bool isErrorStanza() const; + +protected: + void generateAndSetNextId(); + void parse(const QDomElement &element); + /// \endcond + +private: + static uint s_uniqeIdNo; + QString m_to; + QString m_from; + QString m_id; + QString m_lang; + QXmppStanza::Error m_error; + QXmppElementList m_extensions; +}; + +#endif // QXMPPSTANZA_H diff --git a/src/base/QXmppStream.cpp b/src/base/QXmppStream.cpp new file mode 100644 index 00000000..d9f7ff88 --- /dev/null +++ b/src/base/QXmppStream.cpp @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#include "QXmppConstants.h" +#include "QXmppLogger.h" +#include "QXmppPacket.h" +#include "QXmppStream.h" +#include "QXmppUtils.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static bool randomSeeded = false; +static const QByteArray streamRootElementEnd = ""; + +class QXmppStreamPrivate +{ +public: + QXmppStreamPrivate(); + + QByteArray dataBuffer; + QSslSocket* socket; + + // stream state + QByteArray streamStart; +}; + +QXmppStreamPrivate::QXmppStreamPrivate() + : socket(0) +{ +} + +/// Constructs a base XMPP stream. +/// +/// \param parent + +QXmppStream::QXmppStream(QObject *parent) + : QXmppLoggable(parent), + d(new QXmppStreamPrivate) +{ + // Make sure the random number generator is seeded + if (!randomSeeded) + { + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); + randomSeeded = true; + } +} + +/// Destroys a base XMPP stream. + +QXmppStream::~QXmppStream() +{ + delete d; +} + +/// Disconnects from the remote host. +/// + +void QXmppStream::disconnectFromHost() +{ + sendData(streamRootElementEnd); + if (d->socket) + { + d->socket->flush(); + d->socket->disconnectFromHost(); + } +} + +/// Handles a stream start event, which occurs when the underlying transport +/// becomes ready (socket connected, encryption started). +/// +/// If you redefine handleStart(), make sure to call the base class's method. + +void QXmppStream::handleStart() +{ + d->dataBuffer.clear(); + d->streamStart.clear(); +} + +/// Returns true if the stream is connected. +/// + +bool QXmppStream::isConnected() const +{ + return d->socket && + d->socket->state() == QAbstractSocket::ConnectedState; +} + +/// Sends raw data to the peer. +/// +/// \param data + +bool QXmppStream::sendData(const QByteArray &data) +{ + logSent(QString::fromUtf8(data)); + if (!d->socket || d->socket->state() != QAbstractSocket::ConnectedState) + return false; + return d->socket->write(data) == data.size(); +} + +/// Sends an XMPP packet to the peer. +/// +/// \param packet + +bool QXmppStream::sendPacket(const QXmppPacket &packet) +{ + // prepare packet + QByteArray data; + QXmlStreamWriter xmlStream(&data); + packet.toXml(&xmlStream); + + // send packet + return sendData(data); +} + +/// Returns the QSslSocket used for this stream. +/// + +QSslSocket *QXmppStream::socket() const +{ + return d->socket; +} + +/// Sets the QSslSocket used for this stream. +/// + +void QXmppStream::setSocket(QSslSocket *socket) +{ + bool check; + Q_UNUSED(check); + + d->socket = socket; + if (!d->socket) + return; + + // socket events + check = connect(socket, SIGNAL(connected()), + this, SLOT(_q_socketConnected())); + Q_ASSERT(check); + + check = connect(socket, SIGNAL(disconnected()), + this, SLOT(_q_socketDisconnected())); + Q_ASSERT(check); + + check = connect(socket, SIGNAL(encrypted()), + this, SLOT(_q_socketEncrypted())); + Q_ASSERT(check); + + check = connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(_q_socketError(QAbstractSocket::SocketError))); + + check = connect(socket, SIGNAL(readyRead()), + this, SLOT(_q_socketReadyRead())); + Q_ASSERT(check); + + // relay signals + check = connect(socket, SIGNAL(disconnected()), + this, SIGNAL(disconnected())); + Q_ASSERT(check); +} + +void QXmppStream::_q_socketConnected() +{ + info(QString("Socket connected to %1 %2").arg( + d->socket->peerAddress().toString(), + QString::number(d->socket->peerPort()))); + handleStart(); +} + +void QXmppStream::_q_socketDisconnected() +{ + info("Socket disconnected"); +} + +void QXmppStream::_q_socketEncrypted() +{ + debug("Socket encrypted"); + handleStart(); +} + +void QXmppStream::_q_socketError(QAbstractSocket::SocketError socketError) +{ + Q_UNUSED(socketError); + warning(QString("Socket error: " + socket()->errorString())); +} + +void QXmppStream::_q_socketReadyRead() +{ + d->dataBuffer.append(d->socket->readAll()); + + // FIXME : maybe these QRegExps could be static? + QRegExp startStreamRegex("^(<\\?xml.*\\?>)?\\s*"); + startStreamRegex.setMinimal(true); + QRegExp endStreamRegex("$"); + endStreamRegex.setMinimal(true); + + // check whether we need to add stream start / end elements + QByteArray completeXml = d->dataBuffer; + const QString strData = QString::fromUtf8(d->dataBuffer); + bool streamStart = false; + if (d->streamStart.isEmpty() && strData.contains(startStreamRegex)) + streamStart = true; + else + completeXml.prepend(d->streamStart); + if (!strData.contains(endStreamRegex)) + completeXml.append(streamRootElementEnd); + + // check whether we have a valid XML document + QDomDocument doc; + if (!doc.setContent(completeXml, true)) + return; + + // remove data from buffer + logReceived(strData); + d->dataBuffer.clear(); + if (streamStart) + d->streamStart = startStreamRegex.cap(0).toUtf8(); + + // process stream start + if (streamStart) + handleStream(doc.documentElement()); + + // process stanzas + QDomElement nodeRecv = doc.documentElement().firstChildElement(); + while (!nodeRecv.isNull()) { + handleStanza(nodeRecv); + nodeRecv = nodeRecv.nextSiblingElement(); + } +} + + diff --git a/src/base/QXmppStream.h b/src/base/QXmppStream.h new file mode 100644 index 00000000..bcbb7616 --- /dev/null +++ b/src/base/QXmppStream.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPSTREAM_H +#define QXMPPSTREAM_H + +#include +#include +#include "QXmppLogger.h" + +class QDomElement; +class QSslSocket; +class QXmppPacket; +class QXmppStreamPrivate; + +/// \brief The QXmppStream class is the base class for all XMPP streams. +/// + +class QXmppStream : public QXmppLoggable +{ + Q_OBJECT + +public: + QXmppStream(QObject *parent); + ~QXmppStream(); + + virtual bool isConnected() const; + bool sendPacket(const QXmppPacket&); + +signals: + /// This signal is emitted when the stream is connected. + void connected(); + + /// This signal is emitted when the stream is disconnected. + void disconnected(); + +protected: + // Access to underlying socket + QSslSocket *socket() const; + void setSocket(QSslSocket *socket); + + // Overridable methods + virtual void handleStart(); + + /// Handles an incoming XMPP stanza. + /// + /// \param element + virtual void handleStanza(const QDomElement &element) = 0; + + /// Handles an incoming XMPP stream start. + /// + /// \param element + virtual void handleStream(const QDomElement &element) = 0; + +public slots: + virtual void disconnectFromHost(); + virtual bool sendData(const QByteArray&); + +private slots: + void _q_socketConnected(); + void _q_socketDisconnected(); + void _q_socketEncrypted(); + void _q_socketError(QAbstractSocket::SocketError error); + void _q_socketReadyRead(); + +private: + QXmppStreamPrivate * const d; +}; + +#endif // QXMPPSTREAM_H diff --git a/src/base/QXmppStreamFeatures.cpp b/src/base/QXmppStreamFeatures.cpp new file mode 100644 index 00000000..241f676f --- /dev/null +++ b/src/base/QXmppStreamFeatures.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include "QXmppConstants.h" +#include "QXmppStreamFeatures.h" + +QXmppStreamFeatures::QXmppStreamFeatures() + : m_bindMode(Disabled), + m_sessionMode(Disabled), + m_nonSaslAuthMode(Disabled), + m_tlsMode(Disabled) +{ +} + +QXmppStreamFeatures::Mode QXmppStreamFeatures::bindMode() const +{ + return m_bindMode; +} + +void QXmppStreamFeatures::setBindMode(QXmppStreamFeatures::Mode mode) +{ + m_bindMode = mode; +} + +QXmppStreamFeatures::Mode QXmppStreamFeatures::sessionMode() const +{ + return m_sessionMode; +} + +void QXmppStreamFeatures::setSessionMode(Mode mode) +{ + m_sessionMode = mode; +} + +QXmppStreamFeatures::Mode QXmppStreamFeatures::nonSaslAuthMode() const +{ + return m_nonSaslAuthMode; +} + +void QXmppStreamFeatures::setNonSaslAuthMode(QXmppStreamFeatures::Mode mode) +{ + m_nonSaslAuthMode = mode; +} + +QList QXmppStreamFeatures::authMechanisms() const +{ + return m_authMechanisms; +} + +void QXmppStreamFeatures::setAuthMechanisms(QList &mechanisms) +{ + m_authMechanisms = mechanisms; +} + +QList QXmppStreamFeatures::compressionMethods() const +{ + return m_compressionMethods; +} + +void QXmppStreamFeatures::setCompressionMethods(QList &methods) +{ + m_compressionMethods = methods; +} + +QXmppStreamFeatures::Mode QXmppStreamFeatures::tlsMode() const +{ + return m_tlsMode; +} + +void QXmppStreamFeatures::setTlsMode(QXmppStreamFeatures::Mode mode) +{ + m_tlsMode = mode; +} + +bool QXmppStreamFeatures::isStreamFeatures(const QDomElement &element) +{ + return element.namespaceURI() == ns_stream && + element.tagName() == "features"; +} + +static QXmppStreamFeatures::Mode readFeature(const QDomElement &element, const char *tagName, const char *tagNs) +{ + QDomElement subElement = element.firstChildElement(tagName); + if (subElement.namespaceURI() == tagNs) + { + if (!subElement.firstChildElement("required").isNull()) + return QXmppStreamFeatures::Required; + else + return QXmppStreamFeatures::Enabled; + } else { + return QXmppStreamFeatures::Disabled; + } +} + +void QXmppStreamFeatures::parse(const QDomElement &element) +{ + m_bindMode = readFeature(element, "bind", ns_bind); + m_sessionMode = readFeature(element, "session", ns_session); + m_nonSaslAuthMode = readFeature(element, "auth", ns_authFeature); + m_tlsMode = readFeature(element, "starttls", ns_tls); + + // parse advertised compression methods + QDomElement compression = element.firstChildElement("compression"); + if (compression.namespaceURI() == ns_compressFeature) + { + QDomElement subElement = compression.firstChildElement("method"); + while(!subElement.isNull()) + { + if (subElement.text() == QLatin1String("zlib")) + m_compressionMethods << QXmppConfiguration::ZlibCompression; + subElement = subElement.nextSiblingElement("method"); + } + } + + // parse advertised SASL Authentication mechanisms + QDomElement mechs = element.firstChildElement("mechanisms"); + if (mechs.namespaceURI() == ns_sasl) + { + QDomElement subElement = mechs.firstChildElement("mechanism"); + while(!subElement.isNull()) + { + if (subElement.text() == QLatin1String("PLAIN")) + m_authMechanisms << QXmppConfiguration::SASLPlain; + else if (subElement.text() == QLatin1String("DIGEST-MD5")) + m_authMechanisms << QXmppConfiguration::SASLDigestMD5; + else if (subElement.text() == QLatin1String("ANONYMOUS")) + m_authMechanisms << QXmppConfiguration::SASLAnonymous; + else if (subElement.text() == QLatin1String("X-FACEBOOK-PLATFORM")) + m_authMechanisms << QXmppConfiguration::SASLXFacebookPlatform; + subElement = subElement.nextSiblingElement("mechanism"); + } + } +} + +static void writeFeature(QXmlStreamWriter *writer, const char *tagName, const char *tagNs, QXmppStreamFeatures::Mode mode) +{ + if (mode != QXmppStreamFeatures::Disabled) + { + writer->writeStartElement(tagName); + writer->writeAttribute("xmlns", tagNs); + if (mode == QXmppStreamFeatures::Required) + writer->writeEmptyElement("required"); + writer->writeEndElement(); + } +} + +void QXmppStreamFeatures::toXml(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("stream:features"); + writeFeature(writer, "bind", ns_bind, m_bindMode); + writeFeature(writer, "session", ns_session, m_sessionMode); + writeFeature(writer, "auth", ns_authFeature, m_nonSaslAuthMode); + writeFeature(writer, "starttls", ns_tls, m_tlsMode); + + if (!m_compressionMethods.isEmpty()) + { + writer->writeStartElement("compression"); + writer->writeAttribute("xmlns", ns_compressFeature); + for (int i = 0; i < m_compressionMethods.size(); i++) + { + writer->writeStartElement("method"); + switch (m_compressionMethods[i]) + { + case QXmppConfiguration::ZlibCompression: + writer->writeCharacters("zlib"); + break; + } + writer->writeEndElement(); + } + writer->writeEndElement(); + } + if (!m_authMechanisms.isEmpty()) + { + writer->writeStartElement("mechanisms"); + writer->writeAttribute("xmlns", ns_sasl); + for (int i = 0; i < m_authMechanisms.size(); i++) + { + writer->writeStartElement("mechanism"); + switch (m_authMechanisms[i]) + { + case QXmppConfiguration::SASLPlain: + writer->writeCharacters("PLAIN"); + break; + case QXmppConfiguration::SASLDigestMD5: + writer->writeCharacters("DIGEST-MD5"); + break; + case QXmppConfiguration::SASLAnonymous: + writer->writeCharacters("ANONYMOUS"); + break; + case QXmppConfiguration::SASLXFacebookPlatform: + writer->writeCharacters("X-FACEBOOK-PLATFORM"); + break; + } + writer->writeEndElement(); + } + writer->writeEndElement(); + } + writer->writeEndElement(); +} + diff --git a/src/base/QXmppStreamFeatures.h b/src/base/QXmppStreamFeatures.h new file mode 100644 index 00000000..bfc42c64 --- /dev/null +++ b/src/base/QXmppStreamFeatures.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPSTREAMFEATURES_H +#define QXMPPSTREAMFEATURES_H + +#include "QXmppConfiguration.h" +#include "QXmppStanza.h" + +class QXmppStreamFeatures : public QXmppStanza +{ +public: + QXmppStreamFeatures(); + + enum Mode + { + Disabled = 0, + Enabled, + Required + }; + + Mode bindMode() const; + void setBindMode(Mode mode); + + Mode sessionMode() const; + void setSessionMode(Mode mode); + + Mode nonSaslAuthMode() const; + void setNonSaslAuthMode(Mode mode); + + QList authMechanisms() const; + void setAuthMechanisms(QList &mecanisms); + + QList compressionMethods() const; + void setCompressionMethods(QList &methods); + + Mode tlsMode() const; + void setTlsMode(Mode mode); + + /// \cond + void parse(const QDomElement &element); + void toXml(QXmlStreamWriter *writer) const; + /// \endcond + + static bool isStreamFeatures(const QDomElement &element); + +private: + Mode m_bindMode; + Mode m_sessionMode; + Mode m_nonSaslAuthMode; + Mode m_tlsMode; + QList m_authMechanisms; + QList m_compressionMethods; +}; + +#endif diff --git a/src/base/QXmppStreamInitiationIq.cpp b/src/base/QXmppStreamInitiationIq.cpp new file mode 100644 index 00000000..32dd0c78 --- /dev/null +++ b/src/base/QXmppStreamInitiationIq.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include "QXmppConstants.h" +#include "QXmppStreamInitiationIq.h" +#include "QXmppUtils.h" + +QString QXmppStreamInitiationIq::mimeType() const +{ + return m_mimeType; +} + +void QXmppStreamInitiationIq::setMimeType(const QString &mimeType) +{ + m_mimeType = mimeType; +} + +QXmppStreamInitiationIq::Profile QXmppStreamInitiationIq::profile() const +{ + return m_profile; +} + +void QXmppStreamInitiationIq::setProfile(QXmppStreamInitiationIq::Profile profile) +{ + m_profile = profile; +} + +QXmppElementList QXmppStreamInitiationIq::siItems() const +{ + return m_siItems; +} + +QString QXmppStreamInitiationIq::siId() const +{ + return m_siId; +} + +void QXmppStreamInitiationIq::setSiId(const QString &id) +{ + m_siId = id; +} + +void QXmppStreamInitiationIq::setSiItems(const QXmppElementList &items) +{ + m_siItems = items; +} + +bool QXmppStreamInitiationIq::isStreamInitiationIq(const QDomElement &element) +{ + QDomElement siElement = element.firstChildElement("si"); + return (siElement.namespaceURI() == ns_stream_initiation); +} + +void QXmppStreamInitiationIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement siElement = element.firstChildElement("si"); + m_siId = siElement.attribute("id"); + m_mimeType = siElement.attribute("mime-type"); + if (siElement.attribute("profile") == ns_stream_initiation_file_transfer) + m_profile = FileTransfer; + else + m_profile = None; + + QDomElement itemElement = siElement.firstChildElement(); + while (!itemElement.isNull()) + { + m_siItems.append(QXmppElement(itemElement)); + itemElement = itemElement.nextSiblingElement(); + } +} + +void QXmppStreamInitiationIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("si"); + writer->writeAttribute("xmlns", ns_stream_initiation); + helperToXmlAddAttribute(writer, "id", m_siId); + helperToXmlAddAttribute(writer, "mime-type", m_mimeType); + if (m_profile == FileTransfer) + helperToXmlAddAttribute(writer, "profile", ns_stream_initiation_file_transfer); + foreach (const QXmppElement &item, m_siItems) + item.toXml(writer); + writer->writeEndElement(); +} + diff --git a/src/base/QXmppStreamInitiationIq.h b/src/base/QXmppStreamInitiationIq.h new file mode 100644 index 00000000..27739b46 --- /dev/null +++ b/src/base/QXmppStreamInitiationIq.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPSTREAMINITIATIONIQ_H +#define QXMPPSTREAMINITIATIONIQ_H + +#include + +#include "QXmppIq.h" + +class QDomElement; +class QXmlStreamWriter; + +class QXmppStreamInitiationIq : public QXmppIq +{ +public: + enum Profile { + None = 0, + FileTransfer, + }; + + QString mimeType() const; + void setMimeType(const QString &mimeType); + + QXmppStreamInitiationIq::Profile profile() const; + void setProfile(QXmppStreamInitiationIq::Profile profile); + + QString siId() const; + void setSiId(const QString &id); + + QXmppElementList siItems() const; + void setSiItems(const QXmppElementList &items); + + static bool isStreamInitiationIq(const QDomElement &element); + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString m_mimeType; + Profile m_profile; + QString m_siId; + QXmppElementList m_siItems; +}; + +#endif diff --git a/src/base/QXmppStun.cpp b/src/base/QXmppStun.cpp new file mode 100644 index 00000000..16cef928 --- /dev/null +++ b/src/base/QXmppStun.cpp @@ -0,0 +1,2581 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#define QXMPP_DEBUG_STUN + +#include +#include +#include +#include +#include + +#include "QXmppStun.h" +#include "QXmppUtils.h" + +#define ID_SIZE 12 +#define STUN_RTO_INTERVAL 500 +#define STUN_RTO_MAX 7 + +static const quint32 STUN_MAGIC = 0x2112A442; +static const quint16 STUN_HEADER = 20; +static const quint8 STUN_IPV4 = 0x01; +static const quint8 STUN_IPV6 = 0x02; + +enum AttributeType { + MappedAddress = 0x0001, // RFC5389 + ChangeRequest = 0x0003, // RFC5389 + SourceAddress = 0x0004, // RFC5389 + ChangedAddress = 0x0005, // RFC5389 + Username = 0x0006, // RFC5389 + MessageIntegrity = 0x0008, // RFC5389 + ErrorCode = 0x0009, // RFC5389 + ChannelNumber = 0x000c, // RFC5766 : TURN + Lifetime = 0x000d, // RFC5766 : TURN + XorPeerAddress = 0x0012, // RFC5766 : TURN + DataAttr = 0x0013, // RFC5766 : TURN + Realm = 0x0014, // RFC5389 + Nonce = 0x0015, // RFC5389 + XorRelayedAddress= 0x0016, // RFC5766 : TURN + EvenPort = 0x0018, // RFC5766 : TURN + RequestedTransport=0x0019, // RFC5766 : TURN + XorMappedAddress = 0x0020, // RFC5389 + ReservationToken = 0x0022, // RFC5766 : TURN + Priority = 0x0024, // RFC5245 + UseCandidate = 0x0025, // RFC5245 + Software = 0x8022, // RFC5389 + Fingerprint = 0x8028, // RFC5389 + IceControlled = 0x8029, // RFC5245 + IceControlling = 0x802a, // RFC5245 + OtherAddress = 0x802c, // RFC5780 +}; + +// FIXME : we need to set local preference to discriminate between +// multiple IP addresses +static quint32 candidatePriority(const QXmppJingleCandidate &candidate, int localPref = 65535) +{ + int typePref; + switch (candidate.type()) + { + case QXmppJingleCandidate::HostType: + typePref = 126; + break; + case QXmppJingleCandidate::PeerReflexiveType: + typePref = 110; + break; + case QXmppJingleCandidate::ServerReflexiveType: + typePref = 100; + break; + default: + typePref = 0; + } + + return (1 << 24) * typePref + \ + (1 << 8) * localPref + \ + (256 - candidate.component()); +} + +static bool isIPv6LinkLocalAddress(const QHostAddress &addr) +{ + if (addr.protocol() != QAbstractSocket::IPv6Protocol) + return false; + Q_IPV6ADDR ipv6addr = addr.toIPv6Address(); + return (((ipv6addr[0] << 8) + ipv6addr[1]) & 0xffc0) == 0xfe80; +} + +static bool decodeAddress(QDataStream &stream, quint16 a_length, QHostAddress &address, quint16 &port, const QByteArray &xorId = QByteArray()) +{ + if (a_length < 4) + return false; + quint8 reserved, protocol; + quint16 rawPort; + stream >> reserved; + stream >> protocol; + stream >> rawPort; + if (xorId.isEmpty()) + port = rawPort; + else + port = rawPort ^ (STUN_MAGIC >> 16); + if (protocol == STUN_IPV4) + { + if (a_length != 8) + return false; + quint32 addr; + stream >> addr; + if (xorId.isEmpty()) + address = QHostAddress(addr); + else + address = QHostAddress(addr ^ STUN_MAGIC); + } else if (protocol == STUN_IPV6) { + if (a_length != 20) + return false; + Q_IPV6ADDR addr; + stream.readRawData((char*)&addr, sizeof(addr)); + if (!xorId.isEmpty()) + { + QByteArray xpad; + QDataStream(&xpad, QIODevice::WriteOnly) << STUN_MAGIC; + xpad += xorId; + for (int i = 0; i < 16; i++) + addr[i] ^= xpad[i]; + } + address = QHostAddress(addr); + } else { + return false; + } + return true; +} + +static void encodeAddress(QDataStream &stream, quint16 type, const QHostAddress &address, quint16 port, const QByteArray &xorId = QByteArray()) +{ + const quint8 reserved = 0; + if (address.protocol() == QAbstractSocket::IPv4Protocol) + { + stream << type; + stream << quint16(8); + stream << reserved; + stream << quint8(STUN_IPV4); + quint32 addr = address.toIPv4Address(); + if (!xorId.isEmpty()) + { + port ^= (STUN_MAGIC >> 16); + addr ^= STUN_MAGIC; + } + stream << port; + stream << addr; + } else if (address.protocol() == QAbstractSocket::IPv6Protocol) { + stream << type; + stream << quint16(20); + stream << reserved; + stream << quint8(STUN_IPV6); + Q_IPV6ADDR addr = address.toIPv6Address(); + if (!xorId.isEmpty()) + { + port ^= (STUN_MAGIC >> 16); + QByteArray xpad; + QDataStream(&xpad, QIODevice::WriteOnly) << STUN_MAGIC; + xpad += xorId; + for (int i = 0; i < 16; i++) + addr[i] ^= xpad[i]; + } + stream << port; + stream.writeRawData((char*)&addr, sizeof(addr)); + } else { + qWarning("Cannot write STUN attribute for unknown IP version"); + } +} + +static void addAddress(QDataStream &stream, quint16 type, const QHostAddress &host, quint16 port, const QByteArray &xorId = QByteArray()) +{ + if (port && !host.isNull() && + (host.protocol() == QAbstractSocket::IPv4Protocol || + host.protocol() == QAbstractSocket::IPv6Protocol)) + { + encodeAddress(stream, type, host, port, xorId); + } +} + +static void encodeString(QDataStream &stream, quint16 type, const QString &string) +{ + const QByteArray utf8string = string.toUtf8(); + stream << type; + stream << quint16(utf8string.size()); + stream.writeRawData(utf8string.data(), utf8string.size()); + if (utf8string.size() % 4) + { + const QByteArray padding(4 - (utf8string.size() % 4), 0); + stream.writeRawData(padding.data(), padding.size()); + } +} + +static void setBodyLength(QByteArray &buffer, qint16 length) +{ + QDataStream stream(&buffer, QIODevice::WriteOnly); + stream.device()->seek(2); + stream << length; +} + +/// Constructs a new QXmppStunMessage. + +QXmppStunMessage::QXmppStunMessage() + : errorCode(0), + changedPort(0), + mappedPort(0), + otherPort(0), + sourcePort(0), + xorMappedPort(0), + xorPeerPort(0), + xorRelayedPort(0), + useCandidate(false), + m_cookie(STUN_MAGIC), + m_type(0), + m_changeRequest(0), + m_channelNumber(0), + m_lifetime(0), + m_priority(0) +{ + m_id = QByteArray(ID_SIZE, 0); +} + +quint32 QXmppStunMessage::cookie() const +{ + return m_cookie; +} + +void QXmppStunMessage::setCookie(quint32 cookie) +{ + m_cookie = cookie; +} + +QByteArray QXmppStunMessage::id() const +{ + return m_id; +} + +void QXmppStunMessage::setId(const QByteArray &id) +{ + Q_ASSERT(id.size() == ID_SIZE); + m_id = id; +} + +quint16 QXmppStunMessage::messageClass() const +{ + return m_type & 0x0110; +} + +quint16 QXmppStunMessage::messageMethod() const +{ + return m_type & 0x3eef; +} + +quint16 QXmppStunMessage::type() const +{ + return m_type; +} + +void QXmppStunMessage::setType(quint16 type) +{ + m_type = type; +} + +/// Returns the CHANGE-REQUEST attribute, indicating whether to change +/// the IP and / or port from which the response is sent. + +quint32 QXmppStunMessage::changeRequest() const +{ + return m_changeRequest; +} + +/// Sets the CHANGE-REQUEST attribute, indicating whether to change +/// the IP and / or port from which the response is sent. +/// +/// \param changeRequest + +void QXmppStunMessage::setChangeRequest(quint32 changeRequest) +{ + m_changeRequest = changeRequest; + m_attributes << ChangeRequest; +} + +/// Returns the CHANNEL-NUMBER attribute. + +quint16 QXmppStunMessage::channelNumber() const +{ + return m_channelNumber; +} + +/// Sets the CHANNEL-NUMBER attribute. +/// +/// \param channelNumber + +void QXmppStunMessage::setChannelNumber(quint16 channelNumber) +{ + m_channelNumber = channelNumber; + m_attributes << ChannelNumber; +} + +/// Returns the DATA attribute. + +QByteArray QXmppStunMessage::data() const +{ + return m_data; +} + +/// Sets the DATA attribute. + +void QXmppStunMessage::setData(const QByteArray &data) +{ + m_data = data; + m_attributes << DataAttr; +} + +/// Returns the LIFETIME attribute, indicating the duration in seconds for +/// which the server will maintain an allocation. + +quint32 QXmppStunMessage::lifetime() const +{ + return m_lifetime; +} + +/// Sets the LIFETIME attribute, indicating the duration in seconds for +/// which the server will maintain an allocation. +/// +/// \param lifetime + +void QXmppStunMessage::setLifetime(quint32 lifetime) +{ + m_lifetime = lifetime; + m_attributes << Lifetime; +} + +/// Returns the NONCE attribute. + +QByteArray QXmppStunMessage::nonce() const +{ + return m_nonce; +} + +/// Sets the NONCE attribute. +/// +/// \param nonce + +void QXmppStunMessage::setNonce(const QByteArray &nonce) +{ + m_nonce = nonce; + m_attributes << Nonce; +} + +/// Returns the PRIORITY attribute, the priority that would be assigned to +/// a peer reflexive candidate discovered during the ICE check. + +quint32 QXmppStunMessage::priority() const +{ + return m_priority; +} + +/// Sets the PRIORITY attribute, the priority that would be assigned to +/// a peer reflexive candidate discovered during the ICE check. +/// +/// \param priority + +void QXmppStunMessage::setPriority(quint32 priority) +{ + m_priority = priority; + m_attributes << Priority; +} + +/// Returns the REALM attribute. + +QString QXmppStunMessage::realm() const +{ + return m_realm; +} + +/// Sets the REALM attribute. +/// +/// \param realm + +void QXmppStunMessage::setRealm(const QString &realm) +{ + m_realm = realm; + m_attributes << Realm; +} + +/// Returns the REQUESTED-TRANSPORT attribute. + +quint8 QXmppStunMessage::requestedTransport() const +{ + return m_requestedTransport; +} + +/// Sets the REQUESTED-TRANSPORT attribute. +/// +/// \param requestedTransport + +void QXmppStunMessage::setRequestedTransport(quint8 requestedTransport) +{ + m_requestedTransport = requestedTransport; + m_attributes << RequestedTransport; +} + +/// Returns the RESERVATION-TOKEN attribute. + +QByteArray QXmppStunMessage::reservationToken() const +{ + return m_reservationToken; +} + +/// Sets the RESERVATION-TOKEN attribute. +/// +/// \param reservationToken + +void QXmppStunMessage::setReservationToken(const QByteArray &reservationToken) +{ + m_reservationToken = reservationToken; + m_reservationToken.resize(8); + m_attributes << ReservationToken; +} + +/// Returns the SOFTWARE attribute, containing a textual description of the +/// software being used. + +QString QXmppStunMessage::software() const +{ + return m_software; +} + +/// Sets the SOFTWARE attribute, containing a textual description of the +/// software being used. +/// +/// \param software + +void QXmppStunMessage::setSoftware(const QString &software) +{ + m_software = software; + m_attributes << Software; +} + +/// Returns the USERNAME attribute, containing the username to use for +/// authentication. + +QString QXmppStunMessage::username() const +{ + return m_username; +} + +/// Sets the USERNAME attribute, containing the username to use for +/// authentication. +/// +/// \param username + +void QXmppStunMessage::setUsername(const QString &username) +{ + m_username = username; + m_attributes << Username; +} + +/// Decodes a QXmppStunMessage and checks its integrity using the given key. +/// +/// \param buffer +/// \param key +/// \param errors + +bool QXmppStunMessage::decode(const QByteArray &buffer, const QByteArray &key, QStringList *errors) +{ + QStringList silent; + if (!errors) + errors = &silent; + + if (buffer.size() < STUN_HEADER) + { + *errors << QLatin1String("Received a truncated STUN packet"); + return false; + } + + // parse STUN header + QDataStream stream(buffer); + quint16 length; + stream >> m_type; + stream >> length; + stream >> m_cookie; + stream.readRawData(m_id.data(), m_id.size()); + + if (length != buffer.size() - STUN_HEADER) + { + *errors << QLatin1String("Received an invalid STUN packet"); + return false; + } + + // parse STUN attributes + int done = 0; + bool after_integrity = false; + while (done < length) + { + quint16 a_type, a_length; + stream >> a_type; + stream >> a_length; + const int pad_length = 4 * ((a_length + 3) / 4) - a_length; + + // only FINGERPRINT is allowed after MESSAGE-INTEGRITY + if (after_integrity && a_type != Fingerprint) + { + *errors << QString("Skipping attribute %1 after MESSAGE-INTEGRITY").arg(QString::number(a_type)); + stream.skipRawData(a_length + pad_length); + done += 4 + a_length + pad_length; + continue; + } + + if (a_type == Priority) + { + // PRIORITY + if (a_length != sizeof(m_priority)) + return false; + stream >> m_priority; + m_attributes << Priority; + + } else if (a_type == ErrorCode) { + + // ERROR-CODE + if (a_length < 4) + return false; + quint16 reserved; + quint8 errorCodeHigh, errorCodeLow; + stream >> reserved; + stream >> errorCodeHigh; + stream >> errorCodeLow; + errorCode = errorCodeHigh * 100 + errorCodeLow; + QByteArray phrase(a_length - 4, 0); + stream.readRawData(phrase.data(), phrase.size()); + errorPhrase = QString::fromUtf8(phrase); + + } else if (a_type == UseCandidate) { + + // USE-CANDIDATE + if (a_length != 0) + return false; + useCandidate = true; + + } else if (a_type == ChannelNumber) { + + // CHANNEL-NUMBER + if (a_length != 4) + return false; + stream >> m_channelNumber; + stream.skipRawData(2); + m_attributes << ChannelNumber; + + } else if (a_type == DataAttr) { + + // DATA + m_data.resize(a_length); + stream.readRawData(m_data.data(), m_data.size()); + m_attributes << DataAttr; + + } else if (a_type == Lifetime) { + + // LIFETIME + if (a_length != sizeof(m_lifetime)) + return false; + stream >> m_lifetime; + m_attributes << Lifetime; + + } else if (a_type == Nonce) { + + // NONCE + m_nonce.resize(a_length); + stream.readRawData(m_nonce.data(), m_nonce.size()); + m_attributes << Nonce; + + } else if (a_type == Realm) { + + // REALM + QByteArray utf8Realm(a_length, 0); + stream.readRawData(utf8Realm.data(), utf8Realm.size()); + m_realm = QString::fromUtf8(utf8Realm); + m_attributes << Realm; + + } else if (a_type == RequestedTransport) { + + // REQUESTED-TRANSPORT + if (a_length != 4) + return false; + stream >> m_requestedTransport; + stream.skipRawData(3); + m_attributes << RequestedTransport; + + } else if (a_type == ReservationToken) { + + // RESERVATION-TOKEN + if (a_length != 8) + return false; + m_reservationToken.resize(a_length); + stream.readRawData(m_reservationToken.data(), m_reservationToken.size()); + m_attributes << ReservationToken; + + } else if (a_type == Software) { + + // SOFTWARE + QByteArray utf8Software(a_length, 0); + stream.readRawData(utf8Software.data(), utf8Software.size()); + m_software = QString::fromUtf8(utf8Software); + m_attributes << Software; + + } else if (a_type == Username) { + + // USERNAME + QByteArray utf8Username(a_length, 0); + stream.readRawData(utf8Username.data(), utf8Username.size()); + m_username = QString::fromUtf8(utf8Username); + m_attributes << Username; + + } else if (a_type == MappedAddress) { + + // MAPPED-ADDRESS + if (!decodeAddress(stream, a_length, mappedHost, mappedPort)) + { + *errors << QLatin1String("Bad MAPPED-ADDRESS"); + return false; + } + + } else if (a_type == ChangeRequest) { + + // CHANGE-REQUEST + if (a_length != sizeof(m_changeRequest)) + return false; + stream >> m_changeRequest; + m_attributes << ChangeRequest; + + } else if (a_type == SourceAddress) { + + // SOURCE-ADDRESS + if (!decodeAddress(stream, a_length, sourceHost, sourcePort)) + { + *errors << QLatin1String("Bad SOURCE-ADDRESS"); + return false; + } + + } else if (a_type == ChangedAddress) { + + // CHANGED-ADDRESS + if (!decodeAddress(stream, a_length, changedHost, changedPort)) + { + *errors << QLatin1String("Bad CHANGED-ADDRESS"); + return false; + } + + } else if (a_type == OtherAddress) { + + // OTHER-ADDRESS + if (!decodeAddress(stream, a_length, otherHost, otherPort)) + { + *errors << QLatin1String("Bad OTHER-ADDRESS"); + return false; + } + + } else if (a_type == XorMappedAddress) { + + // XOR-MAPPED-ADDRESS + if (!decodeAddress(stream, a_length, xorMappedHost, xorMappedPort, m_id)) + { + *errors << QLatin1String("Bad XOR-MAPPED-ADDRESS"); + return false; + } + + } else if (a_type == XorPeerAddress) { + + // XOR-PEER-ADDRESS + if (!decodeAddress(stream, a_length, xorPeerHost, xorPeerPort, m_id)) + { + *errors << QLatin1String("Bad XOR-PEER-ADDRESS"); + return false; + } + + } else if (a_type == XorRelayedAddress) { + + // XOR-RELAYED-ADDRESS + if (!decodeAddress(stream, a_length, xorRelayedHost, xorRelayedPort, m_id)) + { + *errors << QLatin1String("Bad XOR-RELAYED-ADDRESS"); + return false; + } + + } else if (a_type == MessageIntegrity) { + + // MESSAGE-INTEGRITY + if (a_length != 20) + return false; + QByteArray integrity(20, 0); + stream.readRawData(integrity.data(), integrity.size()); + + // check HMAC-SHA1 + if (!key.isEmpty()) + { + QByteArray copy = buffer.left(STUN_HEADER + done); + setBodyLength(copy, done + 24); + if (integrity != generateHmacSha1(key, copy)) + { + *errors << QLatin1String("Bad message integrity"); + return false; + } + } + + // from here onwards, only FINGERPRINT is allowed + after_integrity = true; + + } else if (a_type == Fingerprint) { + + // FINGERPRINT + if (a_length != 4) + return false; + quint32 fingerprint; + stream >> fingerprint; + + // check CRC32 + QByteArray copy = buffer.left(STUN_HEADER + done); + setBodyLength(copy, done + 8); + const quint32 expected = generateCrc32(copy) ^ 0x5354554eL; + if (fingerprint != expected) + { + *errors << QLatin1String("Bad fingerprint"); + return false; + } + + // stop parsing, no more attributes are allowed + return true; + + } else if (a_type == IceControlling) { + + /// ICE-CONTROLLING + if (a_length != 8) + return false; + iceControlling.resize(a_length); + stream.readRawData(iceControlling.data(), iceControlling.size()); + + } else if (a_type == IceControlled) { + + /// ICE-CONTROLLED + if (a_length != 8) + return false; + iceControlled.resize(a_length); + stream.readRawData(iceControlled.data(), iceControlled.size()); + + } else { + + // Unknown attribute + stream.skipRawData(a_length); + *errors << QString("Skipping unknown attribute %1").arg(QString::number(a_type)); + + } + stream.skipRawData(pad_length); + done += 4 + a_length + pad_length; + } + return true; +} + +/// Encodes the current QXmppStunMessage, optionally calculating the +/// message integrity attribute using the given key. +/// +/// \param key +/// \param addFingerprint + +QByteArray QXmppStunMessage::encode(const QByteArray &key, bool addFingerprint) const +{ + QByteArray buffer; + QDataStream stream(&buffer, QIODevice::WriteOnly); + + // encode STUN header + quint16 length = 0; + stream << m_type; + stream << length; + stream << m_cookie; + stream.writeRawData(m_id.data(), m_id.size()); + + // MAPPED-ADDRESS + addAddress(stream, MappedAddress, mappedHost, mappedPort); + + // CHANGE-REQUEST + if (m_attributes.contains(ChangeRequest)) { + stream << quint16(ChangeRequest); + stream << quint16(sizeof(m_changeRequest)); + stream << m_changeRequest; + } + + // SOURCE-ADDRESS + addAddress(stream, SourceAddress, sourceHost, sourcePort); + + // CHANGED-ADDRESS + addAddress(stream, ChangedAddress, changedHost, changedPort); + + // OTHER-ADDRESS + addAddress(stream, OtherAddress, otherHost, otherPort); + + // XOR-MAPPED-ADDRESS + addAddress(stream, XorMappedAddress, xorMappedHost, xorMappedPort, m_id); + + // XOR-PEER-ADDRESS + addAddress(stream, XorPeerAddress, xorPeerHost, xorPeerPort, m_id); + + // XOR-RELAYED-ADDRESS + addAddress(stream, XorRelayedAddress, xorRelayedHost, xorRelayedPort, m_id); + + // ERROR-CODE + if (errorCode) + { + const quint16 reserved = 0; + const quint8 errorCodeHigh = errorCode / 100; + const quint8 errorCodeLow = errorCode % 100; + const QByteArray phrase = errorPhrase.toUtf8(); + stream << quint16(ErrorCode); + stream << quint16(phrase.size() + 4); + stream << reserved; + stream << errorCodeHigh; + stream << errorCodeLow; + stream.writeRawData(phrase.data(), phrase.size()); + if (phrase.size() % 4) + { + const QByteArray padding(4 - (phrase.size() % 4), 0); + stream.writeRawData(padding.data(), padding.size()); + } + } + + // PRIORITY + if (m_attributes.contains(Priority)) + { + stream << quint16(Priority); + stream << quint16(sizeof(m_priority)); + stream << m_priority; + } + + // USE-CANDIDATE + if (useCandidate) + { + stream << quint16(UseCandidate); + stream << quint16(0); + } + + // CHANNEL-NUMBER + if (m_attributes.contains(ChannelNumber)) { + stream << quint16(ChannelNumber); + stream << quint16(4); + stream << m_channelNumber; + stream << quint16(0); + } + + // DATA + if (m_attributes.contains(DataAttr)) { + stream << quint16(DataAttr); + stream << quint16(m_data.size()); + stream.writeRawData(m_data.data(), m_data.size()); + if (m_data.size() % 4) { + const QByteArray padding(4 - (m_data.size() % 4), 0); + stream.writeRawData(padding.data(), padding.size()); + } + } + + // LIFETIME + if (m_attributes.contains(Lifetime)) { + stream << quint16(Lifetime); + stream << quint16(sizeof(m_lifetime)); + stream << m_lifetime; + } + + // NONCE + if (m_attributes.contains(Nonce)) { + stream << quint16(Nonce); + stream << quint16(m_nonce.size()); + stream.writeRawData(m_nonce.data(), m_nonce.size()); + } + + // REALM + if (m_attributes.contains(Realm)) + encodeString(stream, Realm, m_realm); + + // REQUESTED-TRANSPORT + if (m_attributes.contains(RequestedTransport)) { + const QByteArray reserved(3, 0); + stream << quint16(RequestedTransport); + stream << quint16(4); + stream << m_requestedTransport; + stream.writeRawData(reserved.data(), reserved.size()); + } + + // RESERVATION-TOKEN + if (m_attributes.contains(ReservationToken)) { + stream << quint16(ReservationToken); + stream << quint16(m_reservationToken.size()); + stream.writeRawData(m_reservationToken.data(), m_reservationToken.size()); + } + + // SOFTWARE + if (m_attributes.contains(Software)) + encodeString(stream, Software, m_software); + + // USERNAME + if (m_attributes.contains(Username)) + encodeString(stream, Username, m_username); + + // ICE-CONTROLLING or ICE-CONTROLLED + if (!iceControlling.isEmpty()) + { + stream << quint16(IceControlling); + stream << quint16(iceControlling.size()); + stream.writeRawData(iceControlling.data(), iceControlling.size()); + } else if (!iceControlled.isEmpty()) { + stream << quint16(IceControlled); + stream << quint16(iceControlled.size()); + stream.writeRawData(iceControlled.data(), iceControlled.size()); + } + + // set body length + setBodyLength(buffer, buffer.size() - STUN_HEADER); + + // MESSAGE-INTEGRITY + if (!key.isEmpty()) + { + setBodyLength(buffer, buffer.size() - STUN_HEADER + 24); + QByteArray integrity = generateHmacSha1(key, buffer); + stream << quint16(MessageIntegrity); + stream << quint16(integrity.size()); + stream.writeRawData(integrity.data(), integrity.size()); + } + + // FINGERPRINT + if (addFingerprint) + { + setBodyLength(buffer, buffer.size() - STUN_HEADER + 8); + quint32 fingerprint = generateCrc32(buffer) ^ 0x5354554eL; + stream << quint16(Fingerprint); + stream << quint16(sizeof(fingerprint)); + stream << fingerprint; + } + + return buffer; +} + +/// If the given packet looks like a STUN message, returns the message +/// type, otherwise returns 0. +/// +/// \param buffer +/// \param cookie +/// \param id + +quint16 QXmppStunMessage::peekType(const QByteArray &buffer, quint32 &cookie, QByteArray &id) +{ + if (buffer.size() < STUN_HEADER) + return 0; + + // parse STUN header + QDataStream stream(buffer); + quint16 type; + quint16 length; + stream >> type; + stream >> length; + stream >> cookie; + + if (length != buffer.size() - STUN_HEADER) + return 0; + + id.resize(ID_SIZE); + stream.readRawData(id.data(), id.size()); + return type; +} + +QString QXmppStunMessage::toString() const +{ + QStringList dumpLines; + QString typeName; + switch (messageMethod()) + { + case Binding: typeName = "Binding"; break; + case SharedSecret: typeName = "Shared Secret"; break; + case Allocate: typeName = "Allocate"; break; + case Refresh: typeName = "Refresh"; break; + case Send: typeName = "Send"; break; + case Data: typeName = "Data"; break; + case CreatePermission: typeName = "CreatePermission"; break; + case ChannelBind: typeName = "ChannelBind"; break; + default: typeName = "Unknown"; break; + } + switch (messageClass()) + { + case Request: typeName += " Request"; break; + case Indication: typeName += " Indication"; break; + case Response: typeName += " Response"; break; + case Error: typeName += " Error"; break; + default: break; + } + dumpLines << QString(" type %1 (%2)") + .arg(typeName) + .arg(QString::number(m_type)); + dumpLines << QString(" id %1").arg(QString::fromAscii(m_id.toHex())); + + // attributes + if (m_attributes.contains(ChannelNumber)) + dumpLines << QString(" * CHANNEL-NUMBER %1").arg(QString::number(m_channelNumber)); + if (errorCode) + dumpLines << QString(" * ERROR-CODE %1 %2") + .arg(QString::number(errorCode), errorPhrase); + if (m_attributes.contains(Lifetime)) + dumpLines << QString(" * LIFETIME %1").arg(QString::number(m_lifetime)); + if (m_attributes.contains(Nonce)) + dumpLines << QString(" * NONCE %1").arg(QString::fromLatin1(m_nonce)); + if (m_attributes.contains(Realm)) + dumpLines << QString(" * REALM %1").arg(m_realm); + if (m_attributes.contains(RequestedTransport)) + dumpLines << QString(" * REQUESTED-TRANSPORT 0x%1").arg(QString::number(m_requestedTransport, 16)); + if (m_attributes.contains(ReservationToken)) + dumpLines << QString(" * RESERVATION-TOKEN %1").arg(QString::fromAscii(m_reservationToken.toHex())); + if (m_attributes.contains(Software)) + dumpLines << QString(" * SOFTWARE %1").arg(m_software); + if (m_attributes.contains(Username)) + dumpLines << QString(" * USERNAME %1").arg(m_username); + if (mappedPort) + dumpLines << QString(" * MAPPED-ADDRESS %1 %2") + .arg(mappedHost.toString(), QString::number(mappedPort)); + if (m_attributes.contains(ChangeRequest)) + dumpLines << QString(" * CHANGE-REQUEST %1") + .arg(QString::number(m_changeRequest)); + if (sourcePort) + dumpLines << QString(" * SOURCE-ADDRESS %1 %2") + .arg(sourceHost.toString(), QString::number(sourcePort)); + if (changedPort) + dumpLines << QString(" * CHANGED-ADDRESS %1 %2") + .arg(changedHost.toString(), QString::number(changedPort)); + if (otherPort) + dumpLines << QString(" * OTHER-ADDRESS %1 %2") + .arg(otherHost.toString(), QString::number(otherPort)); + if (xorMappedPort) + dumpLines << QString(" * XOR-MAPPED-ADDRESS %1 %2") + .arg(xorMappedHost.toString(), QString::number(xorMappedPort)); + if (xorPeerPort) + dumpLines << QString(" * XOR-PEER-ADDRESS %1 %2") + .arg(xorPeerHost.toString(), QString::number(xorPeerPort)); + if (xorRelayedPort) + dumpLines << QString(" * XOR-RELAYED-ADDRESS %1 %2") + .arg(xorRelayedHost.toString(), QString::number(xorRelayedPort)); + if (m_attributes.contains(Priority)) + dumpLines << QString(" * PRIORITY %1").arg(QString::number(m_priority)); + if (!iceControlling.isEmpty()) + dumpLines << QString(" * ICE-CONTROLLING %1") + .arg(QString::fromAscii(iceControlling.toHex())); + if (!iceControlled.isEmpty()) + dumpLines << QString(" * ICE-CONTROLLED %1") + .arg(QString::fromAscii(iceControlled.toHex())); + + return dumpLines.join("\n"); +} + +/// Constructs a new QXmppStunTransaction. +/// +/// \param request +/// \param receiver + +QXmppStunTransaction::QXmppStunTransaction(const QXmppStunMessage &request, QObject *receiver) + : QXmppLoggable(receiver), + m_request(request), + m_tries(0) +{ + bool check; + Q_UNUSED(check); + + check = connect(this, SIGNAL(writeStun(QXmppStunMessage)), + receiver, SLOT(writeStun(QXmppStunMessage))); + Q_ASSERT(check); + + check = connect(this, SIGNAL(finished()), + receiver, SLOT(transactionFinished())); + Q_ASSERT(check); + + // RTO timer + m_retryTimer = new QTimer(this); + m_retryTimer->setSingleShot(true); + check = connect(m_retryTimer, SIGNAL(timeout()), + this, SLOT(retry())); + + // send packet immediately + m_tries++; + emit writeStun(m_request); + m_retryTimer->start(STUN_RTO_INTERVAL); +} + +void QXmppStunTransaction::readStun(const QXmppStunMessage &response) +{ + if (response.messageClass() == QXmppStunMessage::Error || + response.messageClass() == QXmppStunMessage::Response) { + m_response = response; + emit finished(); + } +} + +/// Returns the STUN request. + +QXmppStunMessage QXmppStunTransaction::request() const +{ + return m_request; +} + +/// Returns the STUN response. + +QXmppStunMessage QXmppStunTransaction::response() const +{ + return m_response; +} + +void QXmppStunTransaction::retry() +{ + if (m_tries >= STUN_RTO_MAX) { + m_response.setType(QXmppStunMessage::Error); + m_response.errorPhrase = QLatin1String("Request timed out"); + emit finished(); + return; + } + + // resend request + m_tries++; + emit writeStun(m_request); + m_retryTimer->start(2 * m_retryTimer->interval()); +} + +/// Constructs a new QXmppTurnAllocation. +/// +/// \param parent + +QXmppTurnAllocation::QXmppTurnAllocation(QObject *parent) + : QXmppLoggable(parent), + m_relayedPort(0), + m_turnPort(0), + m_channelNumber(0x4000), + m_lifetime(600), + m_state(UnconnectedState) +{ + bool check; + Q_UNUSED(check); + + socket = new QUdpSocket(this); + check = connect(socket, SIGNAL(readyRead()), + this, SLOT(readyRead())); + Q_ASSERT(check); + + m_timer = new QTimer(this); + m_timer->setSingleShot(true); + check = connect(m_timer, SIGNAL(timeout()), + this, SLOT(refresh())); + Q_ASSERT(check); + + // channels are valid 600s, we refresh every 500s + m_channelTimer = new QTimer(this); + m_channelTimer->setInterval(500 * 1000); + check = connect(m_channelTimer, SIGNAL(timeout()), + this, SLOT(refreshChannels())); + Q_ASSERT(check); +} + +/// Destroys the TURN allocation. + +QXmppTurnAllocation::~QXmppTurnAllocation() +{ + if (m_state == ConnectedState) + disconnectFromHost(); +} + +/// Allocates the TURN allocation. + +void QXmppTurnAllocation::connectToHost() +{ + if (m_state != UnconnectedState) + return; + + // start listening for UDP + if (socket->state() == QAbstractSocket::UnconnectedState) { + if (!socket->bind()) { + warning("Could not start listening for TURN"); + return; + } + } + + // send allocate request + QXmppStunMessage request; + request.setType(QXmppStunMessage::Allocate | QXmppStunMessage::Request); + request.setId(generateRandomBytes(12)); + request.setLifetime(m_lifetime); + request.setRequestedTransport(0x11); + m_transactions << new QXmppStunTransaction(request, this); + + // update state + setState(ConnectingState); +} + +/// Releases the TURN allocation. + +void QXmppTurnAllocation::disconnectFromHost() +{ + m_channelTimer->stop(); + m_timer->stop(); + + // clear channels and any outstanding transactions + m_channels.clear(); + foreach (QXmppStunTransaction *transaction, m_transactions) + delete transaction; + m_transactions.clear(); + + // end allocation + if (m_state == ConnectedState) { + QXmppStunMessage request; + request.setType(QXmppStunMessage::Refresh | QXmppStunMessage::Request); + request.setId(generateRandomBytes(12)); + request.setNonce(m_nonce); + request.setRealm(m_realm); + request.setUsername(m_username); + request.setLifetime(0); + m_transactions << new QXmppStunTransaction(request, this); + + setState(ClosingState); + } else { + setState(UnconnectedState); + } +} + +void QXmppTurnAllocation::readyRead() +{ + QByteArray buffer; + QHostAddress remoteHost; + quint16 remotePort; + while (socket->hasPendingDatagrams()) { + const qint64 size = socket->pendingDatagramSize(); + buffer.resize(size); + socket->readDatagram(buffer.data(), buffer.size(), &remoteHost, &remotePort); + handleDatagram(buffer, remoteHost, remotePort); + } +} + +void QXmppTurnAllocation::handleDatagram(const QByteArray &buffer, const QHostAddress &remoteHost, quint16 remotePort) +{ + // demultiplex channel data + if (buffer.size() >= 4 && (buffer[0] & 0xc0) == 0x40) { + QDataStream stream(buffer); + quint16 channel, length; + stream >> channel; + stream >> length; + if (m_state == ConnectedState && m_channels.contains(channel) && length <= buffer.size() - 4) { + emit datagramReceived(buffer.mid(4, length), m_channels[channel].first, + m_channels[channel].second); + } + return; + } + + // parse STUN message + QXmppStunMessage message; + QStringList errors; + if (!message.decode(buffer, QByteArray(), &errors)) { + foreach (const QString &error, errors) + warning(error); + return; + } + +#ifdef QXMPP_DEBUG_STUN + logReceived(QString("TURN packet from %1 port %2\n%3").arg( + remoteHost.toString(), + QString::number(remotePort), + message.toString())); +#endif + + // find transaction + foreach (QXmppStunTransaction *transaction, m_transactions) { + if (transaction->request().id() == message.id() && + transaction->request().messageMethod() == message.messageMethod()) { + transaction->readStun(message); + return; + } + } +} + +/// Refresh allocation. + +void QXmppTurnAllocation::refresh() +{ + QXmppStunMessage request; + request.setType(QXmppStunMessage::Refresh | QXmppStunMessage::Request); + request.setId(generateRandomBytes(12)); + request.setNonce(m_nonce); + request.setRealm(m_realm); + request.setUsername(m_username); + m_transactions << new QXmppStunTransaction(request, this); +} + +/// Refresh channel bindings. + +void QXmppTurnAllocation::refreshChannels() +{ + foreach (quint16 channel, m_channels.keys()) { + QXmppStunMessage request; + request.setType(QXmppStunMessage::ChannelBind | QXmppStunMessage::Request); + request.setId(generateRandomBytes(12)); + request.setNonce(m_nonce); + request.setRealm(m_realm); + request.setUsername(m_username); + request.setChannelNumber(channel); + request.xorPeerHost = m_channels[channel].first; + request.xorPeerPort = m_channels[channel].second; + m_transactions << new QXmppStunTransaction(request, this); + } +} + +/// Returns the relayed host address, i.e. the address on the server +/// used to communicate with peers. + +QHostAddress QXmppTurnAllocation::relayedHost() const +{ + return m_relayedHost; +} + +/// Returns the relayed port, i.e. the port on the server used to communicate +/// with peers. + +quint16 QXmppTurnAllocation::relayedPort() const +{ + return m_relayedPort; +} + +/// Sets the password used to authenticate with the TURN server. +/// +/// \param password + +void QXmppTurnAllocation::setPassword(const QString &password) +{ + m_password = password; +} + +/// Sets the TURN server to use. +/// +/// \param host The address of the TURN server. +/// \param port The port of the TURN server. + +void QXmppTurnAllocation::setServer(const QHostAddress &host, quint16 port) +{ + m_turnHost = host; + m_turnPort = port; +} + +/// Sets the \a user used for authentication with the TURN server. +/// +/// \param user + +void QXmppTurnAllocation::setUser(const QString &user) +{ + m_username = user; +} + +/// Returns the current state of the allocation. +/// + +QXmppTurnAllocation::AllocationState QXmppTurnAllocation::state() const +{ + return m_state; +} + +void QXmppTurnAllocation::setState(AllocationState state) +{ + if (state == m_state) + return; + m_state = state; + if (m_state == ConnectedState) { + emit connected(); + } else if (m_state == UnconnectedState) { + m_timer->stop(); + emit disconnected(); + } +} + +void QXmppTurnAllocation::transactionFinished() +{ + QXmppStunTransaction *transaction = qobject_cast(sender()); + if (!transaction || !m_transactions.removeAll(transaction)) + return; + transaction->deleteLater(); + + // handle authentication + const QXmppStunMessage reply = transaction->response(); + if (reply.messageClass() == QXmppStunMessage::Error && + reply.errorCode == 401 && + (reply.nonce() != m_nonce && reply.realm() != m_realm)) + { + // update long-term credentials + m_nonce = reply.nonce(); + m_realm = reply.realm(); + QCryptographicHash hash(QCryptographicHash::Md5); + hash.addData((m_username + ":" + m_realm + ":" + m_password).toUtf8()); + m_key = hash.result(); + + // retry request + QXmppStunMessage request(transaction->request()); + request.setId(generateRandomBytes(12)); + request.setNonce(m_nonce); + request.setRealm(m_realm); + request.setUsername(m_username); + m_transactions << new QXmppStunTransaction(request, this); + return; + } + + const quint16 method = transaction->request().messageMethod(); + if (method == QXmppStunMessage::Allocate) { + + if (reply.messageClass() == QXmppStunMessage::Error) { + warning(QString("Allocation failed: %1 %2").arg( + QString::number(reply.errorCode), reply.errorPhrase)); + setState(UnconnectedState); + return; + } + if (reply.xorRelayedHost.isNull() || + reply.xorRelayedHost.protocol() != QAbstractSocket::IPv4Protocol || + !reply.xorRelayedPort) { + warning("Allocation did not yield a valid relayed address"); + setState(UnconnectedState); + return; + } + + // store relayed address + m_relayedHost = reply.xorRelayedHost; + m_relayedPort = reply.xorRelayedPort; + + // schedule refresh + m_lifetime = reply.lifetime(); + m_timer->start((m_lifetime - 60) * 1000); + + setState(ConnectedState); + + } else if (method == QXmppStunMessage::ChannelBind) { + + if (reply.messageClass() == QXmppStunMessage::Error) { + warning(QString("ChannelBind failed: %1 %2").arg( + QString::number(reply.errorCode), reply.errorPhrase)); + + // remove channel + m_channels.remove(transaction->request().channelNumber()); + if (m_channels.isEmpty()) + m_channelTimer->stop(); + return; + } + + } else if (method == QXmppStunMessage::Refresh) { + + if (reply.messageClass() == QXmppStunMessage::Error) { + warning(QString("Refresh failed: %1 %2").arg( + QString::number(reply.errorCode), reply.errorPhrase)); + setState(UnconnectedState); + return; + } + + if (m_state == ClosingState) { + setState(UnconnectedState); + return; + } + + // schedule refresh + m_lifetime = reply.lifetime(); + m_timer->start((m_lifetime - 60) * 1000); + + } +} + +qint64 QXmppTurnAllocation::writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port) +{ + if (m_state != ConnectedState) + return -1; + + const Address addr = qMakePair(host, port); + quint16 channel = m_channels.key(addr); + + if (!channel) { + channel = m_channelNumber++; + m_channels.insert(channel, addr); + + // bind channel + QXmppStunMessage request; + request.setType(QXmppStunMessage::ChannelBind | QXmppStunMessage::Request); + request.setId(generateRandomBytes(12)); + request.setNonce(m_nonce); + request.setRealm(m_realm); + request.setUsername(m_username); + request.setChannelNumber(channel); + request.xorPeerHost = host; + request.xorPeerPort = port; + m_transactions << new QXmppStunTransaction(request, this); + + // schedule refresh + if (!m_channelTimer->isActive()) + m_channelTimer->start(); + } + + // send data + QByteArray channelData; + channelData.reserve(4 + data.size()); + QDataStream stream(&channelData, QIODevice::WriteOnly); + stream << channel; + stream << quint16(data.size()); + stream.writeRawData(data.data(), data.size()); + if (socket->writeDatagram(channelData, m_turnHost, m_turnPort) == channelData.size()) + return data.size(); + else + return -1; +} + +void QXmppTurnAllocation::writeStun(const QXmppStunMessage &message) +{ + socket->writeDatagram(message.encode(m_key), m_turnHost, m_turnPort); +#ifdef QXMPP_DEBUG_STUN + logSent(QString("TURN packet to %1 port %2\n%3").arg( + m_turnHost.toString(), + QString::number(m_turnPort), + message.toString())); +#endif +} + +QXmppIceComponent::Pair::Pair(int component, bool controlling) + : checked(QIODevice::NotOpen), + socket(0), + m_component(component), + m_controlling(controlling) +{ + transaction = generateRandomBytes(ID_SIZE); +} + +quint64 QXmppIceComponent::Pair::priority() const +{ + QXmppJingleCandidate local; + local.setComponent(m_component); + local.setType(socket ? QXmppJingleCandidate::HostType : QXmppJingleCandidate::RelayedType); + local.setPriority(candidatePriority(local)); + + // see RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs + const quint32 G = m_controlling ? local.priority() : remote.priority(); + const quint32 D = m_controlling ? remote.priority() : local.priority(); + return (quint64(1) << 32) * qMin(G, D) + 2 * qMax(G, D) + (G > D ? 1 : 0); +} + +QString QXmppIceComponent::Pair::toString() const +{ + QString str = QString("%1 port %2").arg(remote.host().toString(), QString::number(remote.port())); + if (socket) + str += QString(" (local %1 port %2)").arg(socket->localAddress().toString(), QString::number(socket->localPort())); + else + str += QString(" (relayed)"); + if (!reflexive.host().isNull() && reflexive.port()) + str += QString(" (reflexive %1 port %2)").arg(reflexive.host().toString(), QString::number(reflexive.port())); + return str; +} + +/// Constructs a new QXmppIceComponent. +/// +/// \param controlling +/// \param parent + +QXmppIceComponent::QXmppIceComponent(QObject *parent) + : QXmppLoggable(parent), + m_component(0), + m_activePair(0), + m_fallbackPair(0), + m_iceControlling(false), + m_peerReflexivePriority(0), + m_stunPort(0), + m_stunTries(0), + m_turnConfigured(false) +{ + bool check; + Q_UNUSED(check); + + m_localUser = generateStanzaHash(4); + m_localPassword = generateStanzaHash(22); + + m_timer = new QTimer(this); + m_timer->setInterval(500); + check = connect(m_timer, SIGNAL(timeout()), + this, SLOT(checkCandidates())); + Q_ASSERT(check); + + m_stunTimer = new QTimer(this); + m_stunTimer->setInterval(500); + check = connect(m_stunTimer, SIGNAL(timeout()), + this, SLOT(checkStun())); + Q_ASSERT(check); + + m_turnAllocation = new QXmppTurnAllocation(this); + check = connect(m_turnAllocation, SIGNAL(connected()), + this, SLOT(turnConnected())); + Q_ASSERT(check); + check = connect(m_turnAllocation, SIGNAL(datagramReceived(QByteArray,QHostAddress,quint16)), + this, SLOT(handleDatagram(QByteArray,QHostAddress,quint16))); + Q_ASSERT(check); +} + +/// Destroys the QXmppIceComponent. + +QXmppIceComponent::~QXmppIceComponent() +{ + foreach (Pair *pair, m_pairs) + delete pair; +} + +/// Returns the component id for the current socket, e.g. 1 for RTP +/// and 2 for RTCP. + +int QXmppIceComponent::component() const +{ + return m_component; +} + +/// Sets the component id for the current socket, e.g. 1 for RTP +/// and 2 for RTCP. +/// +/// \param component + +void QXmppIceComponent::setComponent(int component) +{ + m_component = component; + + // calculate peer-reflexive candidate priority + // see RFC 5245 - 7.1.2.1. PRIORITY and USE-CANDIDATE + QXmppJingleCandidate reflexive; + reflexive.setComponent(m_component); + reflexive.setType(QXmppJingleCandidate::PeerReflexiveType); + m_peerReflexivePriority = candidatePriority(reflexive); + + setObjectName(QString("STUN(%1)").arg(QString::number(m_component))); +} + +void QXmppIceComponent::checkCandidates() +{ + debug("Checking remote candidates"); + foreach (Pair *pair, m_pairs) + { + if (m_remoteUser.isEmpty()) + continue; + + // send a binding request + QXmppStunMessage message; + message.setId(pair->transaction); + message.setType(QXmppStunMessage::Binding | QXmppStunMessage::Request); + message.setPriority(m_peerReflexivePriority); + message.setUsername(QString("%1:%2").arg(m_remoteUser, m_localUser)); + if (m_iceControlling) + { + message.iceControlling = QByteArray(8, 0); + message.useCandidate = true; + } else { + message.iceControlled = QByteArray(8, 0); + } + writeStun(message, pair); + } + +} + +void QXmppIceComponent::checkStun() +{ + if (m_stunHost.isNull() || !m_stunPort || m_stunTries > 10) { + m_stunTimer->stop(); + return; + } + + // Send a request to STUN server to determine server-reflexive candidate + foreach (QUdpSocket *socket, m_sockets) + { + QXmppStunMessage msg; + msg.setType(QXmppStunMessage::Binding | QXmppStunMessage::Request); + msg.setId(m_stunId); +#ifdef QXMPP_DEBUG_STUN + logSent(QString("STUN packet to %1 port %2\n%3").arg(m_stunHost.toString(), + QString::number(m_stunPort), msg.toString())); +#endif + socket->writeDatagram(msg.encode(), m_stunHost, m_stunPort); + } + m_stunTries++; +} + +/// Stops ICE connectivity checks and closes the underlying sockets. + +void QXmppIceComponent::close() +{ + foreach (QUdpSocket *socket, m_sockets) + socket->close(); + m_turnAllocation->disconnectFromHost(); + m_timer->stop(); + m_stunTimer->stop(); + m_activePair = 0; +} + +/// Starts ICE connectivity checks. + +void QXmppIceComponent::connectToHost() +{ + if (m_activePair) + return; + + checkCandidates(); + m_timer->start(); +} + +/// Returns true if ICE negotiation completed, false otherwise. + +bool QXmppIceComponent::isConnected() const +{ + return m_activePair != 0; +} + +void QXmppIceComponent::setIceControlling(bool controlling) +{ + m_iceControlling = controlling; +} + +/// Returns the list of local candidates. + +QList QXmppIceComponent::localCandidates() const +{ + return m_localCandidates; +} + +/// Sets the local user fragment. +/// +/// \param user + +void QXmppIceComponent::setLocalUser(const QString &user) +{ + m_localUser = user; +} + +/// Sets the local password. +/// +/// \param password + +void QXmppIceComponent::setLocalPassword(const QString &password) +{ + m_localPassword = password; +} + +/// Adds a remote STUN candidate. + +bool QXmppIceComponent::addRemoteCandidate(const QXmppJingleCandidate &candidate) +{ + if (candidate.component() != m_component || + (candidate.type() != QXmppJingleCandidate::HostType && + candidate.type() != QXmppJingleCandidate::RelayedType && + candidate.type() != QXmppJingleCandidate::ServerReflexiveType) || + candidate.protocol() != "udp" || + (candidate.host().protocol() != QAbstractSocket::IPv4Protocol && + candidate.host().protocol() != QAbstractSocket::IPv6Protocol)) + return false; + + foreach (Pair *pair, m_pairs) + if (pair->remote.host() == candidate.host() && + pair->remote.port() == candidate.port()) + return false; + + foreach (QUdpSocket *socket, m_sockets) + { + // do not pair IPv4 with IPv6 or global with link-local addresses + if (socket->localAddress().protocol() != candidate.host().protocol() || + isIPv6LinkLocalAddress(socket->localAddress()) != isIPv6LinkLocalAddress(candidate.host())) + continue; + + Pair *pair = new Pair(m_component, m_iceControlling); + pair->remote = candidate; + if (isIPv6LinkLocalAddress(pair->remote.host())) + { + QHostAddress remoteHost = pair->remote.host(); + remoteHost.setScopeId(socket->localAddress().scopeId()); + pair->remote.setHost(remoteHost); + } + pair->socket = socket; + m_pairs << pair; + + if (!m_fallbackPair) + m_fallbackPair = pair; + } + + // only use relaying for IPv4 candidates + if (m_turnConfigured && candidate.host().protocol() == QAbstractSocket::IPv4Protocol) { + Pair *pair = new Pair(m_component, m_iceControlling); + pair->remote = candidate; + pair->socket = 0; + m_pairs << pair; + } + return true; +} + +/// Adds a discovered peer-reflexive STUN candidate. + +QXmppIceComponent::Pair *QXmppIceComponent::addRemoteCandidate(QUdpSocket *socket, const QHostAddress &host, quint16 port, quint32 priority) +{ + foreach (Pair *pair, m_pairs) + if (pair->remote.host() == host && + pair->remote.port() == port && + pair->socket == socket) + return pair; + + QXmppJingleCandidate candidate; + candidate.setComponent(m_component); + candidate.setHost(host); + candidate.setId(generateStanzaHash(10)); + candidate.setPort(port); + candidate.setPriority(priority); + candidate.setProtocol("udp"); + candidate.setType(QXmppJingleCandidate::PeerReflexiveType); + + Pair *pair = new Pair(m_component, m_iceControlling); + pair->remote = candidate; + pair->socket = socket; + m_pairs << pair; + + debug(QString("Added candidate %1").arg(pair->toString())); + return pair; +} + +/// Sets the remote user fragment. +/// +/// \param user + +void QXmppIceComponent::setRemoteUser(const QString &user) +{ + m_remoteUser = user; +} + +/// Sets the remote password. +/// +/// \param password + +void QXmppIceComponent::setRemotePassword(const QString &password) +{ + m_remotePassword = password; +} + +/// Sets the list of sockets to use for this component. +/// +/// \param sockets + +void QXmppIceComponent::setSockets(QList sockets) +{ + // clear previous candidates and sockets + m_localCandidates.clear(); + foreach (QUdpSocket *socket, m_sockets) + delete socket; + m_sockets.clear(); + + // store candidates + int foundation = 0; + foreach (QUdpSocket *socket, sockets) + { + socket->setParent(this); + connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); + + QXmppJingleCandidate candidate; + candidate.setComponent(m_component); + candidate.setFoundation(foundation++); + // remove scope ID from IPv6 non-link local addresses + QHostAddress addr(socket->localAddress()); + if (addr.protocol() == QAbstractSocket::IPv6Protocol && + !isIPv6LinkLocalAddress(addr)) { + addr.setScopeId(QString()); + } + candidate.setHost(addr); + candidate.setId(generateStanzaHash(10)); + candidate.setPort(socket->localPort()); + candidate.setProtocol("udp"); + candidate.setType(QXmppJingleCandidate::HostType); + candidate.setPriority(candidatePriority(candidate)); + + m_sockets << socket; + m_localCandidates << candidate; + } + + // start STUN checks + if (!m_stunHost.isNull() && m_stunPort) { + m_stunTries = 0; + checkStun(); + m_stunTimer->start(); + } + + // connect to TURN server + if (m_turnConfigured) + m_turnAllocation->connectToHost(); +} + +/// Sets the STUN server to use to determine server-reflexive addresses +/// and ports. +/// +/// \param host The address of the STUN server. +/// \param port The port of the STUN server. + +void QXmppIceComponent::setStunServer(const QHostAddress &host, quint16 port) +{ + m_stunHost = host; + m_stunPort = port; + m_stunId = generateRandomBytes(ID_SIZE); +} + +/// Sets the TURN server to use to relay packets in double-NAT configurations. +/// +/// \param host The address of the TURN server. +/// \param port The port of the TURN server. + +void QXmppIceComponent::setTurnServer(const QHostAddress &host, quint16 port) +{ + m_turnAllocation->setServer(host, port); + m_turnConfigured = !host.isNull() && port; +} + +/// Sets the \a user used for authentication with the TURN server. +/// +/// \param user + +void QXmppIceComponent::setTurnUser(const QString &user) +{ + m_turnAllocation->setUser(user); +} + +/// Sets the \a password used for authentication with the TURN server. +/// +/// \param password + +void QXmppIceComponent::setTurnPassword(const QString &password) +{ + m_turnAllocation->setPassword(password); +} + +void QXmppIceComponent::readyRead() +{ + QUdpSocket *socket = qobject_cast(sender()); + if (!socket) + return; + + QByteArray buffer; + QHostAddress remoteHost; + quint16 remotePort; + while (socket->hasPendingDatagrams()) { + const qint64 size = socket->pendingDatagramSize(); + buffer.resize(size); + socket->readDatagram(buffer.data(), buffer.size(), &remoteHost, &remotePort); + handleDatagram(buffer, remoteHost, remotePort, socket); + } +} + +void QXmppIceComponent::handleDatagram(const QByteArray &buffer, const QHostAddress &remoteHost, quint16 remotePort, QUdpSocket *socket) +{ + // if this is not a STUN message, emit it + quint32 messageCookie; + QByteArray messageId; + quint16 messageType = QXmppStunMessage::peekType(buffer, messageCookie, messageId); + if (!messageType || messageCookie != STUN_MAGIC) + { + // use this as an opportunity to flag a potential pair + foreach (Pair *pair, m_pairs) { + if (pair->remote.host() == remoteHost && + pair->remote.port() == remotePort) { + m_fallbackPair = pair; + break; + } + } + emit datagramReceived(buffer); + return; + } + + // determine password to use + QString messagePassword; + if (messageId != m_stunId) + { + messagePassword = (messageType & 0xFF00) ? m_remotePassword : m_localPassword; + if (messagePassword.isEmpty()) + return; + } + + // parse STUN message + QXmppStunMessage message; + QStringList errors; + if (!message.decode(buffer, messagePassword.toUtf8(), &errors)) + { + foreach (const QString &error, errors) + warning(error); + return; + } +#ifdef QXMPP_DEBUG_STUN + logReceived(QString("STUN packet from %1 port %2\n%3").arg( + remoteHost.toString(), + QString::number(remotePort), + message.toString())); +#endif + + // check how to handle message + if (message.id() == m_stunId) + { + m_stunTimer->stop(); + + // determine server-reflexive address + QHostAddress reflexiveHost; + quint16 reflexivePort = 0; + if (!message.xorMappedHost.isNull() && message.xorMappedPort != 0) + { + reflexiveHost = message.xorMappedHost; + reflexivePort = message.xorMappedPort; + } + else if (!message.mappedHost.isNull() && message.mappedPort != 0) + { + reflexiveHost = message.mappedHost; + reflexivePort = message.mappedPort; + } else { + warning("STUN server did not provide a reflexive address"); + return; + } + + // check whether this candidates is already known + foreach (const QXmppJingleCandidate &candidate, m_localCandidates) + { + if (candidate.host() == reflexiveHost && + candidate.port() == reflexivePort && + candidate.type() == QXmppJingleCandidate::ServerReflexiveType) + return; + } + + // add the new local candidate + debug(QString("Adding server-reflexive candidate %1 port %2").arg(reflexiveHost.toString(), QString::number(reflexivePort))); + QXmppJingleCandidate candidate; + candidate.setComponent(m_component); + candidate.setHost(reflexiveHost); + candidate.setId(generateStanzaHash(10)); + candidate.setPort(reflexivePort); + candidate.setProtocol("udp"); + candidate.setType(QXmppJingleCandidate::ServerReflexiveType); + candidate.setPriority(candidatePriority(candidate)); + m_localCandidates << candidate; + + emit localCandidatesChanged(); + return; + } + + // process message from peer + Pair *pair = 0; + if (message.type() == (QXmppStunMessage::Binding | QXmppStunMessage::Request)) + { + // add remote candidate + pair = addRemoteCandidate(socket, remoteHost, remotePort, message.priority()); + + // send a binding response + QXmppStunMessage response; + response.setId(message.id()); + response.setType(QXmppStunMessage::Binding | QXmppStunMessage::Response); + response.setUsername(message.username()); + response.xorMappedHost = pair->remote.host(); + response.xorMappedPort = pair->remote.port(); + writeStun(response, pair); + + // update state + if (m_iceControlling || message.useCandidate) + { + debug(QString("ICE reverse check complete %1").arg(pair->toString())); + pair->checked |= QIODevice::ReadOnly; + } + + if (!m_iceControlling && !m_activePair && !m_remoteUser.isEmpty()) + { + // send a triggered connectivity test + QXmppStunMessage message; + message.setId(pair->transaction); + message.setType(QXmppStunMessage::Binding | QXmppStunMessage::Request); + message.setPriority(m_peerReflexivePriority); + message.setUsername(QString("%1:%2").arg(m_remoteUser, m_localUser)); + message.iceControlled = QByteArray(8, 0); + writeStun(message, pair); + } + + } else if (message.type() == (QXmppStunMessage::Binding | QXmppStunMessage::Response)) { + + // find the pair for this transaction + foreach (Pair *ptr, m_pairs) + { + if (ptr->transaction == message.id()) + { + pair = ptr; + break; + } + } + if (!pair) + { + debug(QString("Unknown transaction %1").arg(QString::fromAscii(message.id().toHex()))); + return; + } + // store peer-reflexive address + pair->reflexive.setHost(message.xorMappedHost); + pair->reflexive.setPort(message.xorMappedPort); + +#if 0 + // send a binding indication + QXmppStunMessage indication; + indication.setId(generateRandomBytes(ID_SIZE)); + indication.setType(BindingIndication); + m_socket->writeStun(indication, pair); +#endif + + // outgoing media can flow + debug(QString("ICE forward check complete %1").arg(pair->toString())); + pair->checked |= QIODevice::WriteOnly; + } + + // signal completion + if (pair && pair->checked == QIODevice::ReadWrite) + { + m_timer->stop(); + if (!m_activePair || pair->priority() > m_activePair->priority()) { + info(QString("ICE pair selected %1 (priority: %2)").arg( + pair->toString(), QString::number(pair->priority()))); + const bool wasConnected = (m_activePair != 0); + m_activePair = pair; + if (!wasConnected) + emit connected(); + } + } +} + +void QXmppIceComponent::turnConnected() +{ + // add the new local candidate + debug(QString("Adding relayed candidate %1 port %2").arg( + m_turnAllocation->relayedHost().toString(), + QString::number(m_turnAllocation->relayedPort()))); + QXmppJingleCandidate candidate; + candidate.setComponent(m_component); + candidate.setHost(m_turnAllocation->relayedHost()); + candidate.setId(generateStanzaHash(10)); + candidate.setPort(m_turnAllocation->relayedPort()); + candidate.setProtocol("udp"); + candidate.setType(QXmppJingleCandidate::RelayedType); + candidate.setPriority(candidatePriority(candidate)); + m_localCandidates << candidate; + + emit localCandidatesChanged(); +} + +static QList reservePort(const QList &addresses, quint16 port, QObject *parent) +{ + QList sockets; + foreach (const QHostAddress &address, addresses) { + QUdpSocket *socket = new QUdpSocket(parent); + sockets << socket; + if (!socket->bind(address, port)) { + for (int i = 0; i < sockets.size(); ++i) + delete sockets[i]; + sockets.clear(); + break; + } + } + return sockets; +} + +/// Returns the list of local network addresses. + +QList QXmppIceComponent::discoverAddresses() +{ + QList addresses; + foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) + { + if (!(interface.flags() & QNetworkInterface::IsRunning) || + interface.flags() & QNetworkInterface::IsLoopBack) + continue; + + foreach (const QNetworkAddressEntry &entry, interface.addressEntries()) + { + QHostAddress ip = entry.ip(); + if ((ip.protocol() != QAbstractSocket::IPv4Protocol && + ip.protocol() != QAbstractSocket::IPv6Protocol) || + entry.netmask().isNull()) + continue; + +#ifdef Q_OS_MAC + // FIXME: on Mac OS X, sending IPv6 UDP packets fails + if (ip.protocol() == QAbstractSocket::IPv6Protocol) + continue; +#endif + + // FIXME: for now skip IPv6 link-local addresses, seems to upset + // clients such as empathy + if (isIPv6LinkLocalAddress(ip)) { + ip.setScopeId(interface.name()); + continue; + } + addresses << ip; + } + } + return addresses; +} + +/// Tries to bind \a count UDP sockets on each of the given \a addresses. +/// +/// The port numbers are chosen so that they are consecutive, starting at +/// an even port. This makes them suitable for RTP/RTCP sockets pairs. +/// +/// \param addresses The network address on which to bind the sockets. +/// \param count The number of ports to reserve. +/// \param parent The parent object for the sockets. + +QList QXmppIceComponent::reservePorts(const QList &addresses, int count, QObject *parent) +{ + QList sockets; + if (addresses.isEmpty() || !count) + return sockets; + + const int expectedSize = addresses.size() * count; + quint16 port = 49152; + while (sockets.size() != expectedSize) { + // reserve first port (even number) + if (port % 2) + port++; + QList socketChunk; + while (socketChunk.isEmpty() && port <= 65536 - count) { + socketChunk = reservePort(addresses, port, parent); + if (socketChunk.isEmpty()) + port += 2; + } + if (socketChunk.isEmpty()) + return sockets; + + // reserve other ports + sockets << socketChunk; + for (int i = 1; i < count; ++i) { + socketChunk = reservePort(addresses, ++port, parent); + if (socketChunk.isEmpty()) + break; + sockets << socketChunk; + } + + // cleanup if we failed + if (sockets.size() != expectedSize) { + for (int i = 0; i < sockets.size(); ++i) + delete sockets[i]; + sockets.clear(); + } + } + return sockets; +} + +/// Sends a data packet to the remote party. +/// +/// \param datagram + +qint64 QXmppIceComponent::sendDatagram(const QByteArray &datagram) +{ + Pair *pair = m_activePair ? m_activePair : m_fallbackPair; + if (!pair) + return -1; + if (pair->socket) + return pair->socket->writeDatagram(datagram, pair->remote.host(), pair->remote.port()); + else if (m_turnAllocation->state() == QXmppTurnAllocation::ConnectedState) + return m_turnAllocation->writeDatagram(datagram, pair->remote.host(), pair->remote.port()); + else + return -1; +} + +/// Sends a STUN packet to the remote party. + +qint64 QXmppIceComponent::writeStun(const QXmppStunMessage &message, QXmppIceComponent::Pair *pair) +{ + qint64 ret; + const QString messagePassword = (message.type() & 0xFF00) ? m_localPassword : m_remotePassword; + if (pair->socket) + ret = pair->socket->writeDatagram( + message.encode(messagePassword.toUtf8()), + pair->remote.host(), + pair->remote.port()); + else if (m_turnAllocation->state() == QXmppTurnAllocation::ConnectedState) + ret = m_turnAllocation->writeDatagram( + message.encode(messagePassword.toUtf8()), + pair->remote.host(), + pair->remote.port()); + else + return -1; +#ifdef QXMPP_DEBUG_STUN + logSent(QString("Sent to %1\n%2").arg(pair->toString(), message.toString())); +#endif + return ret; +} + +/// Constructs a new ICE connection. +/// +/// \param controlling +/// \param parent + +QXmppIceConnection::QXmppIceConnection(QObject *parent) + : QXmppLoggable(parent), + m_iceControlling(false), + m_stunPort(0) +{ + bool check; + + m_localUser = generateStanzaHash(4); + m_localPassword = generateStanzaHash(22); + + // timer to limit connection time to 30 seconds + m_connectTimer = new QTimer(this); + m_connectTimer->setInterval(30000); + m_connectTimer->setSingleShot(true); + check = connect(m_connectTimer, SIGNAL(timeout()), + this, SLOT(slotTimeout())); + Q_ASSERT(check); + Q_UNUSED(check); +} + +/// Returns the given component of this ICE connection. +/// +/// \param component + +QXmppIceComponent *QXmppIceConnection::component(int component) +{ + return m_components.value(component); +} + +/// Adds a component to this ICE connection, for instance 1 for RTP +/// or 2 for RTCP. +/// +/// \param component + +void QXmppIceConnection::addComponent(int component) +{ + bool check; + Q_UNUSED(check); + + if (m_components.contains(component)) + { + warning(QString("Already have component %1").arg(QString::number(component))); + return; + } + + QXmppIceComponent *socket = new QXmppIceComponent(this); + socket->setComponent(component); + socket->setIceControlling(m_iceControlling); + socket->setLocalUser(m_localUser); + socket->setLocalPassword(m_localPassword); + socket->setStunServer(m_stunHost, m_stunPort); + socket->setTurnServer(m_turnHost, m_turnPort); + socket->setTurnUser(m_turnUser); + socket->setTurnPassword(m_turnPassword); + + check = connect(socket, SIGNAL(localCandidatesChanged()), + this, SIGNAL(localCandidatesChanged())); + Q_ASSERT(check); + + check = connect(socket, SIGNAL(connected()), + this, SLOT(slotConnected())); + Q_ASSERT(check); + + m_components[component] = socket; +} + +/// Adds a candidate for one of the remote components. +/// +/// \param candidate + +void QXmppIceConnection::addRemoteCandidate(const QXmppJingleCandidate &candidate) +{ + QXmppIceComponent *socket = m_components.value(candidate.component()); + if (!socket) + { + warning(QString("Not adding candidate for unknown component %1").arg( + QString::number(candidate.component()))); + return; + } + socket->addRemoteCandidate(candidate); +} + +/// Binds the local sockets to the specified addresses. +/// +/// \param addresses The addresses on which to listen. + +bool QXmppIceConnection::bind(const QList &addresses) +{ + // reserve ports + QList sockets = QXmppIceComponent::reservePorts(addresses, m_components.size()); + if (sockets.isEmpty() && !addresses.isEmpty()) + return false; + + // assign sockets + QList keys = m_components.keys(); + qSort(keys); + int s = 0; + foreach (int k, keys) { + m_components[k]->setSockets(sockets.mid(s, addresses.size())); + s += addresses.size(); + } + + return true; +} + +/// Closes the ICE connection. + +void QXmppIceConnection::close() +{ + m_connectTimer->stop(); + foreach (QXmppIceComponent *socket, m_components.values()) + socket->close(); +} + +/// Starts ICE connectivity checks. + +void QXmppIceConnection::connectToHost() +{ + if (isConnected() || m_connectTimer->isActive()) + return; + + foreach (QXmppIceComponent *socket, m_components.values()) + socket->connectToHost(); + m_connectTimer->start(); +} + + +/// Returns true if ICE negotiation completed, false otherwise. + +bool QXmppIceConnection::isConnected() const +{ + foreach (QXmppIceComponent *socket, m_components.values()) + if (!socket->isConnected()) + return false; + return true; +} + +void QXmppIceConnection::setIceControlling(bool controlling) +{ + m_iceControlling = controlling; + foreach (QXmppIceComponent *socket, m_components.values()) + socket->setIceControlling(controlling); +} + +/// Returns the list of local HOST CANDIDATES candidates by iterating +/// over the available network interfaces. + +QList QXmppIceConnection::localCandidates() const +{ + QList candidates; + foreach (QXmppIceComponent *socket, m_components.values()) + candidates += socket->localCandidates(); + return candidates; +} + +/// Returns the local user fragment. + +QString QXmppIceConnection::localUser() const +{ + return m_localUser; +} + +/// Sets the local user fragment. +/// +/// You do not usually need to call this as one is automatically generated. +/// +/// \param user + +void QXmppIceConnection::setLocalUser(const QString &user) +{ + m_localUser = user; + foreach (QXmppIceComponent *socket, m_components.values()) + socket->setLocalUser(user); +} + +/// Returns the local password. + +QString QXmppIceConnection::localPassword() const +{ + return m_localPassword; +} + +/// Sets the local password. +/// +/// You do not usually need to call this as one is automatically generated. +/// +/// \param password + +void QXmppIceConnection::setLocalPassword(const QString &password) +{ + m_localPassword = password; + foreach (QXmppIceComponent *socket, m_components.values()) + socket->setLocalPassword(password); +} + +/// Sets the remote user fragment. +/// +/// \param user + +void QXmppIceConnection::setRemoteUser(const QString &user) +{ + foreach (QXmppIceComponent *socket, m_components.values()) + socket->setRemoteUser(user); +} + +/// Sets the remote password. +/// +/// \param password + +void QXmppIceConnection::setRemotePassword(const QString &password) +{ + foreach (QXmppIceComponent *socket, m_components.values()) + socket->setRemotePassword(password); +} + +/// Sets the STUN server to use to determine server-reflexive addresses +/// and ports. +/// +/// \param host The address of the STUN server. +/// \param port The port of the STUN server. + +void QXmppIceConnection::setStunServer(const QHostAddress &host, quint16 port) +{ + m_stunHost = host; + m_stunPort = port; + foreach (QXmppIceComponent *socket, m_components.values()) + socket->setStunServer(host, port); +} + +/// Sets the TURN server to use to relay packets in double-NAT configurations. +/// +/// \param host The address of the TURN server. +/// \param port The port of the TURN server. + +void QXmppIceConnection::setTurnServer(const QHostAddress &host, quint16 port) +{ + m_turnHost = host; + m_turnPort = port; + foreach (QXmppIceComponent *socket, m_components.values()) + socket->setTurnServer(host, port); +} + +/// Sets the \a user used for authentication with the TURN server. +/// +/// \param user + +void QXmppIceConnection::setTurnUser(const QString &user) +{ + m_turnUser = user; + foreach (QXmppIceComponent *socket, m_components.values()) + socket->setTurnUser(user); +} + +/// Sets the \a password used for authentication with the TURN server. +/// +/// \param password + +void QXmppIceConnection::setTurnPassword(const QString &password) +{ + m_turnPassword = password; + foreach (QXmppIceComponent *socket, m_components.values()) + socket->setTurnPassword(password); +} + +void QXmppIceConnection::slotConnected() +{ + foreach (QXmppIceComponent *socket, m_components.values()) + if (!socket->isConnected()) + return; + info(QString("ICE negotiation completed")); + m_connectTimer->stop(); + emit connected(); +} + +void QXmppIceConnection::slotTimeout() +{ + warning(QString("ICE negotiation timed out")); + foreach (QXmppIceComponent *socket, m_components.values()) + socket->close(); + emit disconnected(); +} + diff --git a/src/base/QXmppStun.h b/src/base/QXmppStun.h new file mode 100644 index 00000000..1792d3cb --- /dev/null +++ b/src/base/QXmppStun.h @@ -0,0 +1,440 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPSTUN_H +#define QXMPPSTUN_H + +#include + +#include "QXmppLogger.h" +#include "QXmppJingleIq.h" + +class QDataStream; +class QUdpSocket; +class QTimer; + +/// \internal +/// +/// The QXmppStunMessage class represents a STUN message. +/// + +class QXmppStunMessage +{ +public: + enum MethodType { + Binding = 0x1, + SharedSecret = 0x2, + Allocate = 0x3, + Refresh = 0x4, + Send = 0x6, + Data = 0x7, + CreatePermission = 0x8, + ChannelBind = 0x9, + }; + + enum ClassType { + Request = 0x000, + Indication = 0x010, + Response = 0x100, + Error = 0x110, + }; + + QXmppStunMessage(); + + quint32 cookie() const; + void setCookie(quint32 cookie); + + QByteArray id() const; + void setId(const QByteArray &id); + + quint16 messageClass() const; + quint16 messageMethod() const; + + quint16 type() const; + void setType(quint16 type); + + // attributes + + quint32 changeRequest() const; + void setChangeRequest(quint32 changeRequest); + + quint16 channelNumber() const; + void setChannelNumber(quint16 channelNumber); + + QByteArray data() const; + void setData(const QByteArray &data); + + quint32 lifetime() const; + void setLifetime(quint32 changeRequest); + + QByteArray nonce() const; + void setNonce(const QByteArray &nonce); + + quint32 priority() const; + void setPriority(quint32 priority); + + QString realm() const; + void setRealm(const QString &realm); + + QByteArray reservationToken() const; + void setReservationToken(const QByteArray &reservationToken); + + quint8 requestedTransport() const; + void setRequestedTransport(quint8 requestedTransport); + + QString software() const; + void setSoftware(const QString &software); + + QString username() const; + void setUsername(const QString &username); + + QByteArray encode(const QByteArray &key = QByteArray(), bool addFingerprint = true) const; + bool decode(const QByteArray &buffer, const QByteArray &key = QByteArray(), QStringList *errors = 0); + QString toString() const; + static quint16 peekType(const QByteArray &buffer, quint32 &cookie, QByteArray &id); + + // attributes + int errorCode; + QString errorPhrase; + QByteArray iceControlling; + QByteArray iceControlled; + QHostAddress changedHost; + quint16 changedPort; + QHostAddress mappedHost; + quint16 mappedPort; + QHostAddress otherHost; + quint16 otherPort; + QHostAddress sourceHost; + quint16 sourcePort; + QHostAddress xorMappedHost; + quint16 xorMappedPort; + QHostAddress xorPeerHost; + quint16 xorPeerPort; + QHostAddress xorRelayedHost; + quint16 xorRelayedPort; + bool useCandidate; + +private: + quint32 m_cookie; + QByteArray m_id; + quint16 m_type; + + // attributes + QSet m_attributes; + quint32 m_changeRequest; + quint16 m_channelNumber; + QByteArray m_data; + quint32 m_lifetime; + QByteArray m_nonce; + quint32 m_priority; + QString m_realm; + quint8 m_requestedTransport; + QByteArray m_reservationToken; + QString m_software; + QString m_username; +}; + +/// \internal +/// +/// The QXmppStunTransaction class represents a STUN transaction. +/// + +class QXmppStunTransaction : public QXmppLoggable +{ + Q_OBJECT + +public: + QXmppStunTransaction(const QXmppStunMessage &request, QObject *parent); + QXmppStunMessage request() const; + QXmppStunMessage response() const; + +signals: + void finished(); + void writeStun(const QXmppStunMessage &request); + +public slots: + void readStun(const QXmppStunMessage &response); + +private slots: + void retry(); + +private: + QXmppStunMessage m_request; + QXmppStunMessage m_response; + QTimer *m_retryTimer; + int m_tries; +}; + +/// \internal +/// +/// The QXmppTurnAllocation class represents a TURN allocation as defined +/// by RFC 5766 Traversal Using Relays around NAT (TURN). +/// + +class QXmppTurnAllocation : public QXmppLoggable +{ + Q_OBJECT + +public: + enum AllocationState + { + UnconnectedState, + ConnectingState, + ConnectedState, + ClosingState, + }; + + QXmppTurnAllocation(QObject *parent = 0); + ~QXmppTurnAllocation(); + + QHostAddress relayedHost() const; + quint16 relayedPort() const; + AllocationState state() const; + + void setServer(const QHostAddress &host, quint16 port = 3478); + void setUser(const QString &user); + void setPassword(const QString &password); + + qint64 writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port); + +signals: + /// \brief This signal is emitted once TURN allocation succeeds. + void connected(); + + /// \brief This signal is emitted when a data packet is received. + void datagramReceived(const QByteArray &data, const QHostAddress &host, quint16 port); + + /// \brief This signal is emitted when TURN allocation fails. + void disconnected(); + +public slots: + void connectToHost(); + void disconnectFromHost(); + +private slots: + void readyRead(); + void refresh(); + void refreshChannels(); + void transactionFinished(); + void writeStun(const QXmppStunMessage &message); + +private: + void handleDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port); + void setState(AllocationState state); + + QUdpSocket *socket; + QTimer *m_timer; + QTimer *m_channelTimer; + QString m_password; + QString m_username; + QHostAddress m_relayedHost; + quint16 m_relayedPort; + QHostAddress m_turnHost; + quint16 m_turnPort; + + // channels + typedef QPair Address; + quint16 m_channelNumber; + QMap m_channels; + + // state + quint32 m_lifetime; + QByteArray m_key; + QString m_realm; + QByteArray m_nonce; + AllocationState m_state; + QList m_transactions; +}; + +/// \brief The QXmppIceComponent class represents a piece of a media stream +/// requiring a single transport address, as defined by RFC 5245 +/// (Interactive Connectivity Establishment). + +class QXmppIceComponent : public QXmppLoggable +{ + Q_OBJECT + +public: + QXmppIceComponent(QObject *parent=0); + ~QXmppIceComponent(); + void setIceControlling(bool controlling); + void setStunServer(const QHostAddress &host, quint16 port); + void setTurnServer(const QHostAddress &host, quint16 port); + void setTurnUser(const QString &user); + void setTurnPassword(const QString &password); + + QList localCandidates() const; + void setLocalUser(const QString &user); + void setLocalPassword(const QString &password); + + int component() const; + void setComponent(int component); + + bool addRemoteCandidate(const QXmppJingleCandidate &candidate); + void setRemoteUser(const QString &user); + void setRemotePassword(const QString &password); + + bool isConnected() const; + void setSockets(QList sockets); + + static QList discoverAddresses(); + static QList reservePorts(const QList &addresses, int count, QObject *parent = 0); + +public slots: + void close(); + void connectToHost(); + qint64 sendDatagram(const QByteArray &datagram); + +private slots: + void checkCandidates(); + void checkStun(); + void handleDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port, QUdpSocket *socket = 0); + void readyRead(); + void turnConnected(); + +signals: + /// \brief This signal is emitted once ICE negotiation succeeds. + void connected(); + + /// \brief This signal is emitted when a data packet is received. + void datagramReceived(const QByteArray &datagram); + + /// \brief This signal is emitted when the list of local candidates changes. + void localCandidatesChanged(); + +private: + class Pair { + public: + Pair(int component, bool controlling); + quint64 priority() const; + QString toString() const; + + QIODevice::OpenMode checked; + QXmppJingleCandidate remote; + QXmppJingleCandidate reflexive; + QByteArray transaction; + QUdpSocket *socket; + + private: + int m_component; + bool m_controlling; + }; + + Pair *addRemoteCandidate(QUdpSocket *socket, const QHostAddress &host, quint16 port, quint32 priority); + qint64 writeStun(const QXmppStunMessage &message, QXmppIceComponent::Pair *pair); + + int m_component; + + QList m_localCandidates; + QString m_localUser; + QString m_localPassword; + + Pair *m_activePair; + Pair *m_fallbackPair; + bool m_iceControlling; + QList m_pairs; + quint32 m_peerReflexivePriority; + QString m_remoteUser; + QString m_remotePassword; + + QList m_sockets; + QTimer *m_timer; + + // STUN server + QByteArray m_stunId; + QHostAddress m_stunHost; + quint16 m_stunPort; + QTimer *m_stunTimer; + int m_stunTries; + + // TURN server + QXmppTurnAllocation *m_turnAllocation; + bool m_turnConfigured; +}; + +/// \brief The QXmppIceConnection class represents a set of UDP sockets +/// capable of performing Interactive Connectivity Establishment (RFC 5245). +/// + +class QXmppIceConnection : public QXmppLoggable +{ + Q_OBJECT + +public: + QXmppIceConnection(QObject *parent = 0); + + QXmppIceComponent *component(int component); + void addComponent(int component); + void setIceControlling(bool controlling); + + QList localCandidates() const; + QString localUser() const; + void setLocalUser(const QString &user); + QString localPassword() const; + void setLocalPassword(const QString &password); + + void addRemoteCandidate(const QXmppJingleCandidate &candidate); + void setRemoteUser(const QString &user); + void setRemotePassword(const QString &password); + + void setStunServer(const QHostAddress &host, quint16 port = 3478); + void setTurnServer(const QHostAddress &host, quint16 port = 3478); + void setTurnUser(const QString &user); + void setTurnPassword(const QString &password); + + bool bind(const QList &addresses); + bool isConnected() const; + +signals: + /// \brief This signal is emitted once ICE negotiation succeeds. + void connected(); + + /// \brief This signal is emitted when ICE negotiation fails. + void disconnected(); + + /// \brief This signal is emitted when the list of local candidates changes. + void localCandidatesChanged(); + +public slots: + void close(); + void connectToHost(); + +private slots: + void slotConnected(); + void slotTimeout(); + +private: + QTimer *m_connectTimer; + bool m_iceControlling; + QMap m_components; + QString m_localUser; + QString m_localPassword; + QHostAddress m_stunHost; + quint16 m_stunPort; + QHostAddress m_turnHost; + quint16 m_turnPort; + QString m_turnUser; + QString m_turnPassword; +}; + +#endif diff --git a/src/base/QXmppUtils.cpp b/src/base/QXmppUtils.cpp new file mode 100644 index 00000000..1698582f --- /dev/null +++ b/src/base/QXmppUtils.cpp @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "QXmppUtils.h" +#include "QXmppLogger.h" + +// adapted from public domain source by Ross Williams and Eric Durbin +// FIXME : is this valid for big-endian machines? +static quint32 crctable[256] = +{ + 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 +}; + +QDateTime datetimeFromString(const QString &str) +{ + QRegExp tzRe("(Z|([+-])([0-9]{2}):([0-9]{2}))"); + int tzPos = tzRe.indexIn(str, 19); + if (str.size() < 20 || tzPos < 0) + return QDateTime(); + + // process date and time + QDateTime dt = QDateTime::fromString(str.left(19), "yyyy-MM-ddThh:mm:ss"); + dt.setTimeSpec(Qt::UTC); + + // process milliseconds + if (tzPos > 20 && str.at(19) == '.') + { + QString millis = (str.mid(20, tzPos - 20) + "000").left(3); + dt = dt.addMSecs(millis.toInt()); + } + + // process time zone + if (tzRe.cap(1) != "Z") + { + int offset = tzRe.cap(3).toInt() * 3600 + tzRe.cap(4).toInt() * 60; + if (tzRe.cap(2) == "+") + dt = dt.addSecs(-offset); + else + dt = dt.addSecs(offset); + } + return dt; +} + +QString datetimeToString(const QDateTime &dt) +{ + QDateTime utc = dt.toUTC(); + if (utc.time().msec()) + return utc.toString("yyyy-MM-ddThh:mm:ss.zzzZ"); + else + return utc.toString("yyyy-MM-ddThh:mm:ssZ"); +} + +/// Parses a timezone offset (in seconds) from a string. +/// +/// \param str +/// + +int timezoneOffsetFromString(const QString &str) +{ + QRegExp tzRe("(Z|([+-])([0-9]{2}):([0-9]{2}))"); + if (!tzRe.exactMatch(str)) + return 0; + + // No offset from UTC + if (tzRe.cap(1) == "Z") + return 0; + + // Calculate offset + const int offset = tzRe.cap(3).toInt() * 3600 + + tzRe.cap(4).toInt() * 60; + if (tzRe.cap(2) == "-") + return -offset; + else + return offset; +} + +/// Serializes a timezone offset (in seconds) to a string. +/// +/// \param secs + +QString timezoneOffsetToString(int secs) +{ + if (!secs) + return QString::fromLatin1("Z"); + + const QTime tzoTime = QTime(0, 0, 0).addSecs(qAbs(secs)); + return (secs < 0 ? "-" : "+") + tzoTime.toString("hh:mm"); +} + +QString jidToDomain(const QString &jid) +{ + return jidToBareJid(jid).split("@").last(); +} + +QString jidToResource(const QString& jid) +{ + const int pos = jid.indexOf(QChar('/')); + if (pos < 0) + return QString(); + return jid.mid(pos+1); +} + +QString jidToUser(const QString &jid) +{ + const int pos = jid.indexOf(QChar('@')); + if (pos < 0) + return QString(); + return jid.left(pos); +} + +QString jidToBareJid(const QString& jid) +{ + const int pos = jid.indexOf(QChar('/')); + if (pos < 0) + return jid; + return jid.left(pos); +} + +quint32 generateCrc32(const QByteArray &in) +{ + quint32 result = 0xffffffff; + for(int n = 0; n < in.size(); ++n) + result = (result >> 8) ^ (crctable[(result & 0xff) ^ (quint8)in[n]]); + return result ^= 0xffffffff; +} + +static QByteArray generateHmac(QCryptographicHash::Algorithm algorithm, const QByteArray &key, const QByteArray &text) +{ + QCryptographicHash hasher(algorithm); + + const int B = 64; + QByteArray kpad = key + QByteArray(B - key.size(), 0); + + QByteArray ba; + for (int i = 0; i < B; ++i) + ba += kpad[i] ^ 0x5c; + + QByteArray tmp; + for (int i = 0; i < B; ++i) + tmp += kpad[i] ^ 0x36; + hasher.addData(tmp); + hasher.addData(text); + ba += hasher.result(); + + hasher.reset(); + hasher.addData(ba); + return hasher.result(); +} + +QByteArray generateHmacMd5(const QByteArray &key, const QByteArray &text) +{ + return generateHmac(QCryptographicHash::Md5, key, text); +} + +QByteArray generateHmacSha1(const QByteArray &key, const QByteArray &text) +{ + return generateHmac(QCryptographicHash::Sha1, key, text); +} + +/// Generates a random integer x between 0 and N-1. +/// +/// \param N + +int generateRandomInteger(int N) +{ + Q_ASSERT(N > 0 && N <= RAND_MAX); + int val; + while (N <= (val = qrand() / (RAND_MAX/N))) {}; + return val; +} + +/// Returns a random byte array of the specified size. +/// +/// \param length + +QByteArray generateRandomBytes(int length) +{ + QByteArray bytes(length, 'm'); + for (int i = 0; i < length; ++i) + bytes[i] = (char)generateRandomInteger(256); + return bytes; +} + +/// Returns a random alphanumerical string of the specified size. +/// +/// \param length + +QString generateStanzaHash(int length) +{ + const QString somechars = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const int N = somechars.size(); + QString hashResult; + for ( int idx = 0; idx < length; ++idx ) + hashResult += somechars[generateRandomInteger(N)]; + return hashResult; +} + +void helperToXmlAddAttribute(QXmlStreamWriter* stream, const QString& name, + const QString& value) +{ + if(!value.isEmpty()) + stream->writeAttribute(name,value); +} + +void helperToXmlAddDomElement(QXmlStreamWriter* stream, const QDomElement& element, const QStringList &omitNamespaces) +{ + stream->writeStartElement(element.tagName()); + + /* attributes */ + QString xmlns = element.namespaceURI(); + if (!xmlns.isEmpty() && !omitNamespaces.contains(xmlns)) + stream->writeAttribute("xmlns", xmlns); + QDomNamedNodeMap attrs = element.attributes(); + for (int i = 0; i < attrs.size(); i++) + { + QDomAttr attr = attrs.item(i).toAttr(); + stream->writeAttribute(attr.name(), attr.value()); + } + + /* children */ + QDomNode childNode = element.firstChild(); + while (!childNode.isNull()) + { + if (childNode.isElement()) + { + helperToXmlAddDomElement(stream, childNode.toElement(), QStringList() << xmlns); + } else if (childNode.isText()) { + stream->writeCharacters(childNode.toText().data()); + } + childNode = childNode.nextSibling(); + } + stream->writeEndElement(); +} + +void helperToXmlAddTextElement(QXmlStreamWriter* stream, const QString& name, + const QString& value) +{ + if(!value.isEmpty()) + stream->writeTextElement( name, value); + else + stream->writeEmptyElement(name); +} + diff --git a/src/base/QXmppUtils.h b/src/base/QXmppUtils.h new file mode 100644 index 00000000..80d84240 --- /dev/null +++ b/src/base/QXmppUtils.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Authors: + * Manjeet Dahiya + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPUTILS_H +#define QXMPPUTILS_H + +// forward declarations of QXmlStream* classes will not work on Mac, we need to +// include the whole header. +// See http://lists.trolltech.com/qt-interest/2008-07/thread00798-0.html +// for an explanation. +#include + +class QByteArray; +class QDateTime; +class QDomElement; +class QString; +class QStringList; + +// XEP-0082: XMPP Date and Time Profiles +QDateTime datetimeFromString(const QString &str); +QString datetimeToString(const QDateTime &dt); +int timezoneOffsetFromString(const QString &str); +QString timezoneOffsetToString(int secs); + +QString jidToDomain(const QString& jid); +QString jidToResource(const QString& jid); +QString jidToUser(const QString& jid); +QString jidToBareJid(const QString& jid); + +quint32 generateCrc32(const QByteArray &input); +QByteArray generateHmacMd5(const QByteArray &key, const QByteArray &text); +QByteArray generateHmacSha1(const QByteArray &key, const QByteArray &text); +int generateRandomInteger(int N); +QByteArray generateRandomBytes(int length); +QString generateStanzaHash(int length=32); + +void helperToXmlAddAttribute(QXmlStreamWriter* stream, const QString& name, + const QString& value); +void helperToXmlAddDomElement(QXmlStreamWriter* stream, + const QDomElement& element, const QStringList &omitNamespaces); +void helperToXmlAddTextElement(QXmlStreamWriter* stream, const QString& name, + const QString& value); + +#endif // QXMPPUTILS_H diff --git a/src/base/QXmppVCardIq.cpp b/src/base/QXmppVCardIq.cpp new file mode 100644 index 00000000..aaaf4554 --- /dev/null +++ b/src/base/QXmppVCardIq.cpp @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#include +#include + +#include "QXmppVCardIq.h" +#include "QXmppUtils.h" +#include "QXmppConstants.h" + +QString getImageType(const QByteArray &contents) +{ + if (contents.startsWith("\x89PNG\x0d\x0a\x1a\x0a")) + return "image/png"; + else if (contents.startsWith("\x8aMNG")) + return "video/x-mng"; + else if (contents.startsWith("GIF8")) + return "image/gif"; + else if (contents.startsWith("BM")) + return "image/bmp"; + else if (contents.contains("/* XPM */")) + return "image/x-xpm"; + else if (contents.contains("writeStartElement("vCard"); + writer->writeAttribute("xmlns", ns_vcard); + if (m_birthday.isValid()) + helperToXmlAddTextElement(writer, "BDAY", m_birthday.toString("yyyy-MM-dd")); + if (!m_email.isEmpty()) + { + writer->writeStartElement("EMAIL"); + writer->writeEmptyElement("INTERNET"); + helperToXmlAddTextElement(writer, "USERID", m_email); + writer->writeEndElement(); + } + if (!m_fullName.isEmpty()) + helperToXmlAddTextElement(writer, "FN", m_fullName); + if(!m_nickName.isEmpty()) + helperToXmlAddTextElement(writer, "NICKNAME", m_nickName); + if (!m_firstName.isEmpty() || + !m_lastName.isEmpty() || + !m_middleName.isEmpty()) + { + writer->writeStartElement("N"); + if (!m_firstName.isEmpty()) + helperToXmlAddTextElement(writer, "GIVEN", m_firstName); + if (!m_lastName.isEmpty()) + helperToXmlAddTextElement(writer, "FAMILY", m_lastName); + if (!m_middleName.isEmpty()) + helperToXmlAddTextElement(writer, "MIDDLE", m_middleName); + writer->writeEndElement(); + } + if (!m_url.isEmpty()) + helperToXmlAddTextElement(writer, "URL", m_url); + + if(!photo().isEmpty()) + { + writer->writeStartElement("PHOTO"); + QString photoType = m_photoType; + if (photoType.isEmpty()) + photoType = getImageType(m_photo); + helperToXmlAddTextElement(writer, "TYPE", photoType); + helperToXmlAddTextElement(writer, "BINVAL", m_photo.toBase64()); + writer->writeEndElement(); + } + + writer->writeEndElement(); +} + diff --git a/src/base/QXmppVCardIq.h b/src/base/QXmppVCardIq.h new file mode 100644 index 00000000..348c00fc --- /dev/null +++ b/src/base/QXmppVCardIq.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + + +#ifndef QXMPPVCARDIQ_H +#define QXMPPVCARDIQ_H + +#include "QXmppIq.h" +#include +#include +#include + +class QImage; + +/// \brief Represents the XMPP vCard. +/// +/// The functions names are self explanatory. +/// Look at QXmppVCardManager and XEP-0054: vcard-temp for more details. +/// +/// There are many field of XMPP vCard which are not present in +/// this class. File a issue for the same. We will add the requested +/// field to this class. +/// + +class QXmppVCardIq : public QXmppIq +{ +public: + QXmppVCardIq(const QString& bareJid = ""); + + QDate birthday() const; + void setBirthday(const QDate &birthday); + + QString email() const; + void setEmail(const QString&); + + QString firstName() const; + void setFirstName(const QString&); + + QString fullName() const; + void setFullName(const QString&); + + QString lastName() const; + void setLastName(const QString&); + + QString middleName() const; + void setMiddleName(const QString&); + + QString nickName() const; + void setNickName(const QString&); + + QByteArray photo() const; + void setPhoto(const QByteArray&); + + QString photoType() const; + void setPhotoType(const QString &type); + + QString url() const; + void setUrl(const QString&); + + /// \cond + static bool isVCard(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement&); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QDate m_birthday; + QString m_email; + QString m_firstName; + QString m_fullName; + QString m_lastName; + QString m_middleName; + QString m_nickName; + QString m_url; + + // not as 64 base + QByteArray m_photo; + QString m_photoType; +}; + +#endif // QXMPPVCARDIQ_H diff --git a/src/base/QXmppVersionIq.cpp b/src/base/QXmppVersionIq.cpp new file mode 100644 index 00000000..358596b6 --- /dev/null +++ b/src/base/QXmppVersionIq.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#include + +#include "QXmppConstants.h" +#include "QXmppUtils.h" +#include "QXmppVersionIq.h" + +/// Returns the name of the software. +/// + +QString QXmppVersionIq::name() const +{ + return m_name; +} + +/// Sets the name of the software. +/// +/// \param name + +void QXmppVersionIq::setName(const QString &name) +{ + m_name = name; +} + +/// Returns the operating system. +/// + +QString QXmppVersionIq::os() const +{ + return m_os; +} + +/// Sets the operating system. +/// +/// \param os + +void QXmppVersionIq::setOs(const QString &os) +{ + m_os = os; +} + +/// Returns the software version. +/// + +QString QXmppVersionIq::version() const +{ + return m_version; +} + +/// Sets the software version. +/// +/// \param version + +void QXmppVersionIq::setVersion(const QString &version) +{ + m_version = version; +} + +bool QXmppVersionIq::isVersionIq(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + return queryElement.namespaceURI() == ns_version; +} + +void QXmppVersionIq::parseElementFromChild(const QDomElement &element) +{ + QDomElement queryElement = element.firstChildElement("query"); + m_name = queryElement.firstChildElement("name").text(); + m_os = queryElement.firstChildElement("os").text(); + m_version = queryElement.firstChildElement("version").text(); +} + +void QXmppVersionIq::toXmlElementFromChild(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("query"); + writer->writeAttribute("xmlns", ns_version); + + if (!m_name.isEmpty()) + helperToXmlAddTextElement(writer, "name", m_name); + + if (!m_os.isEmpty()) + helperToXmlAddTextElement(writer, "os", m_os); + + if (!m_version.isEmpty()) + helperToXmlAddTextElement(writer, "version", m_version); + + writer->writeEndElement(); +} + diff --git a/src/base/QXmppVersionIq.h b/src/base/QXmppVersionIq.h new file mode 100644 index 00000000..57a800e0 --- /dev/null +++ b/src/base/QXmppVersionIq.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Jeremy Lainé + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * 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. + * + */ + +#ifndef QXMPPVERSIONIQ_H +#define QXMPPVERSIONIQ_H + +#include "QXmppIq.h" + +/// \brief The QXmppVersionIq class represents an IQ for conveying a software +/// version as defined by XEP-0092: Software Version. +/// +/// \ingroup Stanzas + +class QXmppVersionIq : public QXmppIq +{ +public: + QString name() const; + void setName(const QString &name); + + QString os() const; + void setOs(const QString &os); + + QString version() const; + void setVersion(const QString &version); + + /// \cond + static bool isVersionIq(const QDomElement &element); + /// \endcond + +protected: + /// \cond + void parseElementFromChild(const QDomElement &element); + void toXmlElementFromChild(QXmlStreamWriter *writer) const; + /// \endcond + +private: + QString m_name; + QString m_os; + QString m_version; +}; + +#endif diff --git a/src/base/qdnslookup.cpp b/src/base/qdnslookup.cpp new file mode 100644 index 00000000..7b1e7c8f --- /dev/null +++ b/src/base/qdnslookup.cpp @@ -0,0 +1,989 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Jeremy Lainé +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdnslookup.h" +#include "qdnslookup_p.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool); +Q_GLOBAL_STATIC(QThreadStorage, theDnsLookupSeedStorage); + +static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2) +{ + // Lower numbers are more preferred than higher ones. + return r1.preference() < r2.preference(); +} + +/*! + Sorts a list of QDnsMailExchangeRecord objects according to RFC 5321. +*/ + +static void qt_qdnsmailexchangerecord_sort(QList &records) +{ + // If we have no more than one result, we are done. + if (records.size() <= 1) + return; + + // Order the records by preference. + qSort(records.begin(), records.end(), qt_qdnsmailexchangerecord_less_than); + + int i = 0; + while (i < records.size()) { + + // Determine the slice of records with the current preference. + QList slice; + const quint16 slicePreference = records[i].preference(); + for (int j = i; j < records.size(); ++j) { + if (records[j].preference() != slicePreference) + break; + slice << records[j]; + } + + // Randomize the slice of records. + while (!slice.isEmpty()) { + const unsigned int pos = qrand() % slice.size(); + records[i++] = slice.takeAt(pos); + } + } +} + +static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QDnsServiceRecord &r2) +{ + // Order by priority, or if the priorities are equal, + // put zero weight records first. + return r1.priority() < r2.priority() + || (r1.priority() == r2.priority() + && r1.weight() == 0 && r2.weight() > 0); +} + +/*! + Sorts a list of QDnsServiceRecord objects according to RFC 2782. +*/ + +static void qt_qdnsservicerecord_sort(QList &records) +{ + // If we have no more than one result, we are done. + if (records.size() <= 1) + return; + + // Order the records by priority, and for records with an equal + // priority, put records with a zero weight first. + qSort(records.begin(), records.end(), qt_qdnsservicerecord_less_than); + + int i = 0; + while (i < records.size()) { + + // Determine the slice of records with the current priority. + QList slice; + const quint16 slicePriority = records[i].priority(); + unsigned int sliceWeight = 0; + for (int j = i; j < records.size(); ++j) { + if (records[j].priority() != slicePriority) + break; + sliceWeight += records[j].weight(); + slice << records[j]; + } +#ifdef QDNSLOOKUP_DEBUG + qDebug("qt_qdnsservicerecord_sort() : priority %i (size: %i, total weight: %i)", + slicePriority, slice.size(), sliceWeight); +#endif + + // Order the slice of records. + while (!slice.isEmpty()) { + const unsigned int weightThreshold = qrand() % (sliceWeight + 1); + unsigned int summedWeight = 0; + for (int j = 0; j < slice.size(); ++j) { + summedWeight += slice[j].weight(); + if (summedWeight >= weightThreshold) { +#ifdef QDNSLOOKUP_DEBUG + qDebug("qt_qdnsservicerecord_sort() : adding %s %i (weight: %i)", + qPrintable(slice[j].target()), slice[j].port(), + slice[j].weight()); +#endif + // Adjust the slice weight and take the current record. + sliceWeight -= slice[j].weight(); + records[i++] = slice.takeAt(j); + break; + } + } + } + } +} + +/*! + \class QDnsLookup + \brief The QDnsLookup class represents a DNS lookup. + + \inmodule QtNetwork + \ingroup network + + QDnsLookup uses the mechanisms provided by the operating system to perform + DNS lookups. To perform a lookup you need to specify a \l name and \l type + then invoke the \l{QDnsLookup::lookup()}{lookup()} slot. The + \l{QDnsLookup::finished()}{finished()} signal will be emitted upon + completion. + + For example, you can determine which servers an XMPP chat client should + connect to for a given domain with: + + \snippet doc/src/snippets/code/src_network_kernel_qdnslookup.cpp 0 + + Once the request finishes you can handle the results with: + + \snippet doc/src/snippets/code/src_network_kernel_qdnslookup.cpp 1 + + \note If you simply want to find the IP address(es) associated with a host + name, or the host name associated with an IP address you should use + QHostInfo instead. +*/ + +/*! + \enum QDnsLookup::Error + + Indicates all possible error conditions found during the + processing of the DNS lookup. + + \value NoError no error condition. + + \value ResolverError there was an error initializing the system's + DNS resolver. + + \value OperationCancelledError the lookup was aborted using the abort() + method. + + \value InvalidRequestError the requested DNS lookup was invalid. + + \value InvalidReplyError the reply returned by the server was invalid. + + \value ServerFailureError the server encountered an internal failure + while processing the request (SERVFAIL). + + \value ServerRefusedError the server refused to process the request for + security or policy reasons (REFUSED). + + \value NotFoundError the requested domain name does not exist + (NXDOMAIN). +*/ + +/*! + \enum QDnsLookup::Type + + Indicates the type of DNS lookup that was performed. + + \value A IPv4 address records. + + \value AAAA IPv6 address records. + + \value ANY any records. + + \value CNAME canonical name records. + + \value MX mail exchange records. + + \value NS name server records. + + \value PTR pointer records. + + \value SRV service records. + + \value TXT text records. +*/ + +/*! + \fn void QDnsLookup::finished() + + This signal is emitted when the reply has finished processing. +*/ + +/*! + \fn void QDnsLookup::nameChanged(const QString &name) + + This signal is emitted when the lookup \l name changes. + \a name is the new lookup name. +*/ + +/*! + \fn void QDnsLookup::typeChanged(Type type) + + This signal is emitted when the lookup \l type changes. + \a type is the new lookup type. +*/ + +/*! + Constructs a QDnsLookup object and sets \a parent as the parent object. + + The \l type property will default to QDnsLookup::A. +*/ + +QDnsLookup::QDnsLookup(QObject *parent) + : QObject(parent) + , d_ptr(new QDnsLookupPrivate(this)) +{ + qRegisterMetaType(); +} +/*! + Constructs a QDnsLookup object for the given \a type and \a name and sets + \a parent as the parent object. +*/ + +QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent) + : QObject(parent) + , d_ptr(new QDnsLookupPrivate(this)) +{ + Q_D(QDnsLookup); + qRegisterMetaType(); + d->name = name; + d->type = type; +} + +/*! + Destroys the QDnsLookup object. + + It is safe to delete a QDnsLookup object even if it is not finished, you + will simply never receive its results. +*/ + +QDnsLookup::~QDnsLookup() +{ +} + +/*! + \property QDnsLookup::error + \brief the type of error that occurred if the DNS lookup failed, or NoError. +*/ + +QDnsLookup::Error QDnsLookup::error() const +{ + return d_func()->reply.error; +} + +/*! + \property QDnsLookup::errorString + \brief a human-readable description of the error if the DNS lookup failed. +*/ + +QString QDnsLookup::errorString() const +{ + return d_func()->reply.errorString; +} + +/*! + \property QDnsLookup::finished + \brief whether the reply has finished or was aborted. +*/ + +bool QDnsLookup::isFinished() const +{ + return d_func()->isFinished; +} + +/*! + \property QDnsLookup::name + \brief the name to lookup. + + \note The name will be encoded using IDNA, which means it's unsuitable for + querying SRV records compatible with the DNS-SD specification. +*/ + +QString QDnsLookup::name() const +{ + return d_func()->name; +} + +void QDnsLookup::setName(const QString &name) +{ + Q_D(QDnsLookup); + if (name != d->name) { + d->name = name; + emit nameChanged(name); + } +} + +/*! + \property QDnsLookup::type + \brief the type of DNS lookup. +*/ + +QDnsLookup::Type QDnsLookup::type() const +{ + return d_func()->type; +} + +void QDnsLookup::setType(Type type) +{ + Q_D(QDnsLookup); + if (type != d->type) { + d->type = type; + emit typeChanged(type); + } +} + +/*! + Returns the list of canonical name records associated with this lookup. +*/ + +QList QDnsLookup::canonicalNameRecords() const +{ + return d_func()->reply.canonicalNameRecords; +} + +/*! + Returns the list of host address records associated with this lookup. +*/ + +QList QDnsLookup::hostAddressRecords() const +{ + return d_func()->reply.hostAddressRecords; +} + +/*! + Returns the list of mail exchange records associated with this lookup. + + The records are sorted according to + \l{http://www.rfc-editor.org/rfc/rfc5321.txt}{RFC 5321}, so if you use them + to connect to servers, you should try them in the order they are listed. +*/ + +QList QDnsLookup::mailExchangeRecords() const +{ + return d_func()->reply.mailExchangeRecords; +} + +/*! + Returns the list of name server records associated with this lookup. +*/ + +QList QDnsLookup::nameServerRecords() const +{ + return d_func()->reply.nameServerRecords; +} + +/*! + Returns the list of pointer records associated with this lookup. +*/ + +QList QDnsLookup::pointerRecords() const +{ + return d_func()->reply.pointerRecords; +} + +/*! + Returns the list of service records associated with this lookup. + + The records are sorted according to + \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}, so if you use them + to connect to servers, you should try them in the order they are listed. +*/ + +QList QDnsLookup::serviceRecords() const +{ + return d_func()->reply.serviceRecords; +} + +/*! + Returns the list of text records associated with this lookup. +*/ + +QList QDnsLookup::textRecords() const +{ + return d_func()->reply.textRecords; +} + +/*! + Aborts the DNS lookup operation. + + If the lookup is already finished, does nothing. +*/ + +void QDnsLookup::abort() +{ + Q_D(QDnsLookup); + if (d->runnable) { + d->runnable = 0; + d->reply = QDnsLookupReply(); + d->reply.error = QDnsLookup::OperationCancelledError; + d->reply.errorString = tr("Operation cancelled"); + d->isFinished = true; + emit finished(); + } +} + +/*! + Performs the DNS lookup. + + The \l{QDnsLookup::finished()}{finished()} signal is emitted upon completion. +*/ + +void QDnsLookup::lookup() +{ + Q_D(QDnsLookup); + d->isFinished = false; + d->reply = QDnsLookupReply(); + d->runnable = new QDnsLookupRunnable(d->type, QUrl::toAce(d->name)); + connect(d->runnable, SIGNAL(finished(QDnsLookupReply)), + this, SLOT(_q_lookupFinished(QDnsLookupReply)), + Qt::BlockingQueuedConnection); + theDnsLookupThreadPool()->start(d->runnable); +} + +/*! + \class QDnsDomainNameRecord + \brief The QDnsDomainNameRecord class stores information about a domain + name record. + + \inmodule QtNetwork + \ingroup network + + When performing a name server lookup, zero or more records will be returned. + Each record is represented by a QDnsDomainNameRecord instance. + + \sa QDnsLookup +*/ + +/*! + Constructs an empty domain name record object. +*/ + +QDnsDomainNameRecord::QDnsDomainNameRecord() + : d(new QDnsDomainNameRecordPrivate) +{ +} + +/*! + Constructs a copy of \a other. +*/ + +QDnsDomainNameRecord::QDnsDomainNameRecord(const QDnsDomainNameRecord &other) + : d(other.d) +{ +} + +/*! + Destroys a domain name record. +*/ + +QDnsDomainNameRecord::~QDnsDomainNameRecord() +{ +} + +/*! + Returns the name for this record. +*/ + +QString QDnsDomainNameRecord::name() const +{ + return d->name; +} + +/*! + Returns the duration in seconds for which this record is valid. +*/ + +quint32 QDnsDomainNameRecord::timeToLive() const +{ + return d->timeToLive; +} + +/*! + Returns the value for this domain name record. +*/ + +QString QDnsDomainNameRecord::value() const +{ + return d->value; +} + +/*! + Assigns the data of the \a other object to this record object, + and returns a reference to it. +*/ + +QDnsDomainNameRecord &QDnsDomainNameRecord::operator=(const QDnsDomainNameRecord &other) +{ + d = other.d; + return *this; +} + +/*! + \class QDnsHostAddressRecord + \brief The QDnsHostAddressRecord class stores information about a host + address record. + + \inmodule QtNetwork + \ingroup network + + When performing an address lookup, zero or more records will be + returned. Each record is represented by a QDnsHostAddressRecord instance. + + \sa QDnsLookup +*/ + +/*! + Constructs an empty host address record object. +*/ + +QDnsHostAddressRecord::QDnsHostAddressRecord() + : d(new QDnsHostAddressRecordPrivate) +{ +} + +/*! + Constructs a copy of \a other. +*/ + +QDnsHostAddressRecord::QDnsHostAddressRecord(const QDnsHostAddressRecord &other) + : d(other.d) +{ +} + +/*! + Destroys a host address record. +*/ + +QDnsHostAddressRecord::~QDnsHostAddressRecord() +{ +} + +/*! + Returns the name for this record. +*/ + +QString QDnsHostAddressRecord::name() const +{ + return d->name; +} + +/*! + Returns the duration in seconds for which this record is valid. +*/ + +quint32 QDnsHostAddressRecord::timeToLive() const +{ + return d->timeToLive; +} + +/*! + Returns the value for this host address record. +*/ + +QHostAddress QDnsHostAddressRecord::value() const +{ + return d->value; +} + +/*! + Assigns the data of the \a other object to this record object, + and returns a reference to it. +*/ + +QDnsHostAddressRecord &QDnsHostAddressRecord::operator=(const QDnsHostAddressRecord &other) +{ + d = other.d; + return *this; +} + +/*! + \class QDnsMailExchangeRecord + \brief The QDnsMailExchangeRecord class stores information about a DNS MX record. + + \inmodule QtNetwork + \ingroup network + + When performing a lookup on a service, zero or more records will be + returned. Each record is represented by a QDnsMailExchangeRecord instance. + + The meaning of the fields is defined in + \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}. + + \sa QDnsLookup +*/ + +/*! + Constructs an empty mail exchange record object. +*/ + +QDnsMailExchangeRecord::QDnsMailExchangeRecord() + : d(new QDnsMailExchangeRecordPrivate) +{ +} + +/*! + Constructs a copy of \a other. +*/ + +QDnsMailExchangeRecord::QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other) + : d(other.d) +{ +} + +/*! + Destroys a mail exchange record. +*/ + +QDnsMailExchangeRecord::~QDnsMailExchangeRecord() +{ +} + +/*! + Returns the domain name of the mail exchange for this record. +*/ + +QString QDnsMailExchangeRecord::exchange() const +{ + return d->exchange; +} + +/*! + Returns the name for this record. +*/ + +QString QDnsMailExchangeRecord::name() const +{ + return d->name; +} + +/*! + Returns the preference for this record. +*/ + +quint16 QDnsMailExchangeRecord::preference() const +{ + return d->preference; +} + +/*! + Returns the duration in seconds for which this record is valid. +*/ + +quint32 QDnsMailExchangeRecord::timeToLive() const +{ + return d->timeToLive; +} + +/*! + Assigns the data of the \a other object to this record object, + and returns a reference to it. +*/ + +QDnsMailExchangeRecord &QDnsMailExchangeRecord::operator=(const QDnsMailExchangeRecord &other) +{ + d = other.d; + return *this; +} + +/*! + \class QDnsServiceRecord + \brief The QDnsServiceRecord class stores information about a DNS SRV record. + + \inmodule QtNetwork + \ingroup network + + When performing a lookup on a service, zero or more records will be + returned. Each record is represented by a QDnsServiceRecord instance. + + The meaning of the fields is defined in + \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}. + + \sa QDnsLookup +*/ + +/*! + Constructs an empty service record object. +*/ + +QDnsServiceRecord::QDnsServiceRecord() + : d(new QDnsServiceRecordPrivate) +{ +} + +/*! + Constructs a copy of \a other. +*/ + +QDnsServiceRecord::QDnsServiceRecord(const QDnsServiceRecord &other) + : d(other.d) +{ +} + +/*! + Destroys a service record. +*/ + +QDnsServiceRecord::~QDnsServiceRecord() +{ +} + +/*! + Returns the name for this record. +*/ + +QString QDnsServiceRecord::name() const +{ + return d->name; +} + +/*! + Returns the port on the target host for this service record. +*/ + +quint16 QDnsServiceRecord::port() const +{ + return d->port; +} + +/*! + Returns the priority for this service record. + + A client must attempt to contact the target host with the lowest-numbered + priority. +*/ + +quint16 QDnsServiceRecord::priority() const +{ + return d->priority; +} + +/*! + Returns the domain name of the target host for this service record. +*/ + +QString QDnsServiceRecord::target() const +{ + return d->target; +} + +/*! + Returns the duration in seconds for which this record is valid. +*/ + +quint32 QDnsServiceRecord::timeToLive() const +{ + return d->timeToLive; +} + +/*! + Returns the weight for this service record. + + The weight field specifies a relative weight for entries with the same + priority. Entries with higher weights should be selected with a higher + probability. +*/ + +quint16 QDnsServiceRecord::weight() const +{ + return d->weight; +} + +/*! + Assigns the data of the \a other object to this record object, + and returns a reference to it. +*/ + +QDnsServiceRecord &QDnsServiceRecord::operator=(const QDnsServiceRecord &other) +{ + d = other.d; + return *this; +} + +/*! + \class QDnsTextRecord + \brief The QDnsTextRecord class stores information about a DNS TXT record. + + \inmodule QtNetwork + \ingroup network + + When performing a text lookup, zero or more records will be + returned. Each record is represented by a QDnsTextRecord instance. + + The meaning of the fields is defined in + \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}. + + \sa QDnsLookup +*/ + +/*! + Constructs an empty text record object. +*/ + +QDnsTextRecord::QDnsTextRecord() + : d(new QDnsTextRecordPrivate) +{ +} + +/*! + Constructs a copy of \a other. +*/ + +QDnsTextRecord::QDnsTextRecord(const QDnsTextRecord &other) + : d(other.d) +{ +} + +/*! + Destroys a text record. +*/ + +QDnsTextRecord::~QDnsTextRecord() +{ +} + +/*! + Returns the name for this text record. +*/ + +QString QDnsTextRecord::name() const +{ + return d->name; +} + +/*! + Returns the duration in seconds for which this record is valid. +*/ + +quint32 QDnsTextRecord::timeToLive() const +{ + return d->timeToLive; +} + +/*! + Returns the values for this text record. +*/ + +QList QDnsTextRecord::values() const +{ + return d->values; +} + +/*! + Assigns the data of the \a other object to this record object, + and returns a reference to it. +*/ + +QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other) +{ + d = other.d; + return *this; +} + +void QDnsLookupPrivate::_q_lookupFinished(const QDnsLookupReply &_reply) +{ + Q_Q(QDnsLookup); + if (runnable == q->sender()) { +#ifdef QDNSLOOKUP_DEBUG + qDebug("DNS reply for %s: %i (%s)", qPrintable(name), _reply.error, qPrintable(_reply.errorString)); +#endif + reply = _reply; + runnable = 0; + isFinished = true; + emit q->finished(); + } +} + +void QDnsLookupRunnable::run() +{ + QDnsLookupReply reply; + + // Validate input. + if (requestName.isEmpty()) { + reply.error = QDnsLookup::InvalidRequestError; + reply.errorString = tr("Invalid domain name"); + emit finished(reply); + return; + } + + // Perform request. + query(requestType, requestName, &reply); + + // Sort results. + if (!theDnsLookupSeedStorage()->hasLocalData()) { + qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) ^ reinterpret_cast(this)); + theDnsLookupSeedStorage()->setLocalData(new bool(true)); + } + qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords); + qt_qdnsservicerecord_sort(reply.serviceRecords); + + emit finished(reply); +} + +QDnsLookupThreadPool::QDnsLookupThreadPool() + : signalsConnected(false) +{ + // Run up to 5 lookups in parallel. + setMaxThreadCount(5); +} + +void QDnsLookupThreadPool::start(QRunnable *runnable) +{ + // Ensure threads complete at application destruction. + if (!signalsConnected) { + QMutexLocker signalsLocker(&signalsMutex); + if (!signalsConnected) { + QCoreApplication *app = QCoreApplication::instance(); + if (!app) { + qWarning("QDnsLookup requires a QCoreApplication"); + delete runnable; + return; + } + + moveToThread(app->thread()); + connect(app, SIGNAL(destroyed()), + SLOT(_q_applicationDestroyed()), Qt::DirectConnection); + signalsConnected = true; + } + } + + QThreadPool::start(runnable); +} + +void QDnsLookupThreadPool::_q_applicationDestroyed() +{ + waitForDone(); + signalsConnected = false; +} + +QT_END_NAMESPACE diff --git a/src/base/qdnslookup.h b/src/base/qdnslookup.h new file mode 100644 index 00000000..6f913896 --- /dev/null +++ b/src/base/qdnslookup.h @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Jeremy Lainé +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDNSLOOKUP_H +#define QDNSLOOKUP_H + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Network) + +class QHostAddress; +class QDnsLookupPrivate; +class QDnsDomainNameRecordPrivate; +class QDnsHostAddressRecordPrivate; +class QDnsMailExchangeRecordPrivate; +class QDnsServiceRecordPrivate; +class QDnsTextRecordPrivate; + +class QDnsDomainNameRecord +{ +public: + QDnsDomainNameRecord(); + QDnsDomainNameRecord(const QDnsDomainNameRecord &other); + ~QDnsDomainNameRecord(); + + QString name() const; + quint32 timeToLive() const; + QString value() const; + + QDnsDomainNameRecord &operator=(const QDnsDomainNameRecord &other); + +private: + QSharedDataPointer d; + friend class QDnsLookupRunnable; +}; + +class QDnsHostAddressRecord +{ +public: + QDnsHostAddressRecord(); + QDnsHostAddressRecord(const QDnsHostAddressRecord &other); + ~QDnsHostAddressRecord(); + + QString name() const; + quint32 timeToLive() const; + QHostAddress value() const; + + QDnsHostAddressRecord &operator=(const QDnsHostAddressRecord &other); + +private: + QSharedDataPointer d; + friend class QDnsLookupRunnable; +}; + +class QDnsMailExchangeRecord +{ +public: + QDnsMailExchangeRecord(); + QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other); + ~QDnsMailExchangeRecord(); + + QString exchange() const; + QString name() const; + quint16 preference() const; + quint32 timeToLive() const; + + QDnsMailExchangeRecord &operator=(const QDnsMailExchangeRecord &other); + +private: + QSharedDataPointer d; + friend class QDnsLookupRunnable; +}; + +class QDnsServiceRecord +{ +public: + QDnsServiceRecord(); + QDnsServiceRecord(const QDnsServiceRecord &other); + ~QDnsServiceRecord(); + + QString name() const; + quint16 port() const; + quint16 priority() const; + QString target() const; + quint32 timeToLive() const; + quint16 weight() const; + + QDnsServiceRecord &operator=(const QDnsServiceRecord &other); + +private: + QSharedDataPointer d; + friend class QDnsLookupRunnable; +}; + +class QDnsTextRecord +{ +public: + QDnsTextRecord(); + QDnsTextRecord(const QDnsTextRecord &other); + ~QDnsTextRecord(); + + QString name() const; + quint32 timeToLive() const; + QList values() const; + + QDnsTextRecord &operator=(const QDnsTextRecord &other); + +private: + QSharedDataPointer d; + friend class QDnsLookupRunnable; +}; + +class QDnsLookup : public QObject +{ + Q_OBJECT + Q_ENUMS(Error Type) + Q_PROPERTY(Error error READ error NOTIFY finished) + Q_PROPERTY(QString errorString READ errorString NOTIFY finished) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(Type type READ type WRITE setType NOTIFY typeChanged) + +public: + enum Error + { + NoError = 0, + ResolverError, + OperationCancelledError, + InvalidRequestError, + InvalidReplyError, + ServerFailureError, + ServerRefusedError, + NotFoundError + }; + + enum Type + { + A = 1, + AAAA = 28, + ANY = 255, + CNAME = 5, + MX = 15, + NS = 2, + PTR = 12, + SRV = 33, + TXT = 16 + }; + + QDnsLookup(QObject *parent = 0); + QDnsLookup(Type type, const QString &name, QObject *parent = 0); + ~QDnsLookup(); + + Error error() const; + QString errorString() const; + bool isFinished() const; + + QString name() const; + void setName(const QString &name); + + Type type() const; + void setType(QDnsLookup::Type); + + QList canonicalNameRecords() const; + QList hostAddressRecords() const; + QList mailExchangeRecords() const; + QList nameServerRecords() const; + QList pointerRecords() const; + QList serviceRecords() const; + QList textRecords() const; + + +public Q_SLOTS: + void abort(); + void lookup(); + +Q_SIGNALS: + void finished(); + void nameChanged(const QString &name); + void typeChanged(Type type); + +private: + QDnsLookupPrivate *d_ptr; + Q_DECLARE_PRIVATE(QDnsLookup) + Q_PRIVATE_SLOT(d_func(), void _q_lookupFinished(const QDnsLookupReply &reply)) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#include "qdnslookup_p.h" + +#endif // QDNSLOOKUP_H diff --git a/src/base/qdnslookup_p.h b/src/base/qdnslookup_p.h new file mode 100644 index 00000000..4797f345 --- /dev/null +++ b/src/base/qdnslookup_p.h @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Jeremy Lainé +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDNSLOOKUP_P_H +#define QDNSLOOKUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QDnsLookup class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include + +#include "qdnslookup.h" + +QT_BEGIN_NAMESPACE + +//#define QDNSLOOKUP_DEBUG + +class QDnsLookupRunnable; + +class QDnsLookupReply +{ +public: + QDnsLookupReply() + : error(QDnsLookup::NoError) + { } + + QDnsLookup::Error error; + QString errorString; + + QList canonicalNameRecords; + QList hostAddressRecords; + QList mailExchangeRecords; + QList nameServerRecords; + QList pointerRecords; + QList serviceRecords; + QList textRecords; +}; + +class QDnsLookupPrivate +{ +public: + QDnsLookupPrivate(QDnsLookup *qq) + : isFinished(false) + , type(QDnsLookup::A) + , runnable(0) + , q_ptr(qq) + { } + + void _q_lookupFinished(const QDnsLookupReply &reply); + + bool isFinished; + QString name; + QDnsLookup::Type type; + QDnsLookupReply reply; + QDnsLookupRunnable *runnable; + QDnsLookup *q_ptr; + + Q_DECLARE_PUBLIC(QDnsLookup) +}; + +class QDnsLookupRunnable : public QObject, public QRunnable +{ + Q_OBJECT + +public: + QDnsLookupRunnable(QDnsLookup::Type type, const QByteArray &name) + : requestType(type) + , requestName(name) + { } + void run(); + +signals: + void finished(const QDnsLookupReply &reply); + +private: + static void query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply); + QDnsLookup::Type requestType; + QByteArray requestName; +}; + +class QDnsLookupThreadPool : public QThreadPool +{ + Q_OBJECT + +public: + QDnsLookupThreadPool(); + void start(QRunnable *runnable); + +private slots: + void _q_applicationDestroyed(); + +private: + QMutex signalsMutex; + bool signalsConnected; +}; + +class QDnsRecordPrivate : public QSharedData +{ +public: + QDnsRecordPrivate() + : timeToLive(0) + { } + + QString name; + quint32 timeToLive; +}; + +class QDnsDomainNameRecordPrivate : public QDnsRecordPrivate +{ +public: + QDnsDomainNameRecordPrivate() + { } + + QString value; +}; + +class QDnsHostAddressRecordPrivate : public QDnsRecordPrivate +{ +public: + QDnsHostAddressRecordPrivate() + { } + + QHostAddress value; +}; + +class QDnsMailExchangeRecordPrivate : public QDnsRecordPrivate +{ +public: + QDnsMailExchangeRecordPrivate() + : preference(0) + { } + + QString exchange; + quint16 preference; +}; + +class QDnsServiceRecordPrivate : public QDnsRecordPrivate +{ +public: + QDnsServiceRecordPrivate() + : port(0), + priority(0), + weight(0) + { } + + QString target; + quint16 port; + quint16 priority; + quint16 weight; +}; + +class QDnsTextRecordPrivate : public QDnsRecordPrivate +{ +public: + QDnsTextRecordPrivate() + { } + + QList values; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDnsLookupReply) + +#endif // QDNSLOOKUP_P_H diff --git a/src/base/qdnslookup_stub.cpp b/src/base/qdnslookup_stub.cpp new file mode 100644 index 00000000..df9ed349 --- /dev/null +++ b/src/base/qdnslookup_stub.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Jeremy Lainé +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdnslookup_p.h" + +QT_BEGIN_NAMESPACE + +void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply) +{ + Q_UNUSED(requestType); + Q_UNUSED(requestName); + reply->error = QDnsLookup::ResolverError; + reply->errorString = QLatin1String("QDnsLookup is not implemented for this platform"); +} + +QT_END_NAMESPACE diff --git a/src/base/qdnslookup_symbian.cpp b/src/base/qdnslookup_symbian.cpp new file mode 100644 index 00000000..bed5278e --- /dev/null +++ b/src/base/qdnslookup_symbian.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Jeremy Lainé +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdnslookup_p.h" + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply) +{ + RHostResolver dnsResolver; + RSocketServ dnsSocket; + + // Initialise resolver. + TInt err = dnsSocket.Connect(); + err = dnsResolver.Open(dnsSocket, KAfInet, KProtocolInetUdp); + if (err != KErrNone) { + reply->error = QDnsLookup::ResolverError; + reply->errorString = QLatin1String("RHostResolver::Open failed"); + return; + } + + // Perform DNS query. + TDnsQueryBuf dnsQuery; + TDnsRespSRVBuf dnsResponse; + dnsQuery().SetClass(KDnsRRClassIN); + TPtrC8 queryPtr(reinterpret_cast(requestName.constData()), requestName.size()); + dnsQuery().SetData(queryPtr); + dnsQuery().SetType(requestType); + err = dnsResolver.Query(dnsQuery, dnsResponse); + if (err != KErrNone) { + reply->error = QDnsLookup::NotFoundError; + reply->errorString = QLatin1String("RHostResolver::Query failed"); + return; + } + + // Extract results. + while (err == KErrNone) { + const QByteArray aceName((const char*)dnsResponse().Target().Ptr(), + dnsResponse().Target().Length()); + + QDnsServiceRecord record; + record.d->name = QUrl::fromAce(requestName); + record.d->target = QUrl::fromAce(aceName); + record.d->port = dnsResponse().Port(); + record.d->priority = dnsResponse().Priority(); + record.d->timeToLive = dnsResponse().RRTtl(); + record.d->weight = dnsResponse().Weight(); + reply->serviceRecords.append(record); + + err = dnsResolver.QueryGetNext(dnsResponse); + } +} + +QT_END_NAMESPACE diff --git a/src/base/qdnslookup_unix.cpp b/src/base/qdnslookup_unix.cpp new file mode 100644 index 00000000..f4d1c64c --- /dev/null +++ b/src/base/qdnslookup_unix.cpp @@ -0,0 +1,323 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Jeremy Lainé +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdnslookup_p.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static QMutex local_res_mutex; +typedef int (*dn_expand_proto)(const unsigned char *, const unsigned char *, const unsigned char *, char *, int); +static dn_expand_proto local_dn_expand = 0; +typedef void (*res_nclose_proto)(res_state); +static res_nclose_proto local_res_nclose = 0; +typedef int (*res_ninit_proto)(res_state); +static res_ninit_proto local_res_ninit = 0; +typedef int (*res_nquery_proto)(res_state, const char *, int, int, unsigned char *, int); +static res_nquery_proto local_res_nquery = 0; + +// Custom deleter to close resolver state. + +struct QDnsLookupStateDeleter +{ + static inline void cleanup(struct __res_state *pointer) + { + local_res_nclose(pointer); + } +}; + +static void resolveLibrary() +{ + QLibrary lib(QLatin1String("resolv")); + if (!lib.load()) + return; + + local_dn_expand = dn_expand_proto(lib.resolve("__dn_expand")); + if (!local_dn_expand) + local_dn_expand = dn_expand_proto(lib.resolve("dn_expand")); + + local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose")); + if (!local_res_nclose) + local_res_nclose = res_nclose_proto(lib.resolve("res_9_nclose")); + if (!local_res_nclose) + local_res_nclose = res_nclose_proto(lib.resolve("res_nclose")); + + local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit")); + if (!local_res_ninit) + local_res_ninit = res_ninit_proto(lib.resolve("res_9_ninit")); + if (!local_res_ninit) + local_res_ninit = res_ninit_proto(lib.resolve("res_ninit")); + + local_res_nquery = res_nquery_proto(lib.resolve("__res_nquery")); + if (!local_res_nquery) + local_res_nquery = res_nquery_proto(lib.resolve("res_9_nquery")); + if (!local_res_nquery) + local_res_nquery = res_nquery_proto(lib.resolve("res_nquery")); +} + +void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply) +{ + // Load dn_expand, res_ninit and res_nquery on demand. + static volatile bool triedResolve = false; + if (!triedResolve) { + QMutexLocker locker(&local_res_mutex); + if (!triedResolve) { + resolveLibrary(); + triedResolve = true; + } + } + + // If dn_expand, res_ninit or res_nquery is missing, fail. + if (!local_dn_expand || !local_res_nclose || !local_res_ninit || !local_res_nquery) { + reply->error = QDnsLookup::ResolverError; + reply->errorString = tr("Resolver functions not found"); + return; + } + + // Initialize state. + struct __res_state state; + memset(&state, 0, sizeof(state)); + if (local_res_ninit(&state) < 0) { + reply->error = QDnsLookup::ResolverError; + reply->errorString = tr("Resolver initialization failed"); + return; + } +#ifdef QDNSLOOKUP_DEBUG + state.options |= RES_DEBUG; +#endif + QScopedPointer state_ptr(&state); + + // Perform DNS query. + unsigned char response[PACKETSZ]; + memset(response, 0, sizeof(response)); + const int responseLength = local_res_nquery(&state, requestName, C_IN, requestType, response, sizeof(response)); + + // Check the response header. + HEADER *header = (HEADER*)response; + const int answerCount = ntohs(header->ancount); + switch (header->rcode) { + case NOERROR: + break; + case FORMERR: + reply->error = QDnsLookup::InvalidRequestError; + reply->errorString = tr("Server could not process query"); + return; + case SERVFAIL: + reply->error = QDnsLookup::ServerFailureError; + reply->errorString = tr("Server failure"); + return; + case NXDOMAIN: + reply->error = QDnsLookup::NotFoundError; + reply->errorString = tr("Non existent domain"); + return; + case REFUSED: + reply->error = QDnsLookup::ServerRefusedError; + reply->errorString = tr("Server refused to answer"); + return; + default: + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Invalid reply received"); + return; + } + + // Check the reply is valid. + if (responseLength < int(sizeof(HEADER))) { + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Invalid reply received"); + return; + } + + // Skip the query host, type (2 bytes) and class (2 bytes). + char host[PACKETSZ], answer[PACKETSZ]; + unsigned char *p = response + sizeof(HEADER); + int status = local_dn_expand(response, response + responseLength, p, host, sizeof(host)); + if (status < 0) { + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Could not expand domain name"); + return; + } + p += status + 4; + + // Extract results. + int answerIndex = 0; + while ((p < response + responseLength) && (answerIndex < answerCount)) { + status = local_dn_expand(response, response + responseLength, p, host, sizeof(host)); + if (status < 0) { + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Could not expand domain name"); + return; + } + const QString name = QUrl::fromAce(host); + + p += status; + const quint16 type = (p[0] << 8) | p[1]; + p += 2; // RR type + p += 2; // RR class + const quint32 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + p += 4; + const quint16 size = (p[0] << 8) | p[1]; + p += 2; + + if (type == QDnsLookup::A) { + if (size != 4) { + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Invalid IPv4 address record"); + return; + } + const quint32 addr = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + QDnsHostAddressRecord record; + record.d->name = name; + record.d->timeToLive = ttl; + record.d->value = QHostAddress(addr); + reply->hostAddressRecords.append(record); + } else if (type == QDnsLookup::AAAA) { + if (size != 16) { + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Invalid IPv6 address record"); + return; + } + QDnsHostAddressRecord record; + record.d->name = name; + record.d->timeToLive = ttl; + record.d->value = QHostAddress(p); + reply->hostAddressRecords.append(record); + } else if (type == QDnsLookup::CNAME) { + status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer)); + if (status < 0) { + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Invalid canonical name record"); + return; + } + QDnsDomainNameRecord record; + record.d->name = name; + record.d->timeToLive = ttl; + record.d->value = QUrl::fromAce(answer); + reply->canonicalNameRecords.append(record); + } else if (type == QDnsLookup::NS) { + status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer)); + if (status < 0) { + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Invalid name server record"); + return; + } + QDnsDomainNameRecord record; + record.d->name = name; + record.d->timeToLive = ttl; + record.d->value = QUrl::fromAce(answer); + reply->nameServerRecords.append(record); + } else if (type == QDnsLookup::PTR) { + status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer)); + if (status < 0) { + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Invalid pointer record"); + return; + } + QDnsDomainNameRecord record; + record.d->name = name; + record.d->timeToLive = ttl; + record.d->value = QUrl::fromAce(answer); + reply->pointerRecords.append(record); + } else if (type == QDnsLookup::MX) { + const quint16 preference = (p[0] << 8) | p[1]; + status = local_dn_expand(response, response + responseLength, p + 2, answer, sizeof(answer)); + if (status < 0) { + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Invalid mail exchange record"); + return; + } + QDnsMailExchangeRecord record; + record.d->exchange = QUrl::fromAce(answer); + record.d->name = name; + record.d->preference = preference; + record.d->timeToLive = ttl; + reply->mailExchangeRecords.append(record); + } else if (type == QDnsLookup::SRV) { + const quint16 priority = (p[0] << 8) | p[1]; + const quint16 weight = (p[2] << 8) | p[3]; + const quint16 port = (p[4] << 8) | p[5]; + status = local_dn_expand(response, response + responseLength, p + 6, answer, sizeof(answer)); + if (status < 0) { + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Invalid service record"); + return; + } + QDnsServiceRecord record; + record.d->name = name; + record.d->target = QUrl::fromAce(answer); + record.d->port = port; + record.d->priority = priority; + record.d->timeToLive = ttl; + record.d->weight = weight; + reply->serviceRecords.append(record); + } else if (type == QDnsLookup::TXT) { + unsigned char *txt = p; + QDnsTextRecord record; + record.d->name = name; + record.d->timeToLive = ttl; + while (txt < p + size) { + const unsigned char length = *txt; + txt++; + if (txt + length > p + size) { + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Invalid text record"); + return; + } + record.d->values << QByteArray((char*)txt, length); + txt += length; + } + reply->textRecords.append(record); + } + p += size; + answerIndex++; + } +} + +QT_END_NAMESPACE diff --git a/src/base/qdnslookup_win.cpp b/src/base/qdnslookup_win.cpp new file mode 100644 index 00000000..87d6955a --- /dev/null +++ b/src/base/qdnslookup_win.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Jeremy Lainé +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdnslookup_p.h" + +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static QMutex local_dns_mutex; +typedef DNS_STATUS (*dns_query_utf8_proto)(PCSTR,WORD,DWORD,PIP4_ARRAY,PDNS_RECORD*,PVOID*); +static dns_query_utf8_proto local_dns_query_utf8 = 0; +typedef void (*dns_record_list_free_proto)(PDNS_RECORD,DNS_FREE_TYPE); +static dns_record_list_free_proto local_dns_record_list_free = 0; + +static void resolveLibrary() +{ + QLibrary lib(QLatin1String("dnsapi")); + if (!lib.load()) + return; + + local_dns_query_utf8 = (dns_query_utf8_proto) lib.resolve(QLatin1String("dnsapi"), "DnsQuery_UTF8"); + local_dns_record_list_free = (dns_record_list_free_proto) lib.resolve(QLatin1String("dnsapi"), "DnsRecordListFree"); +} + +void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply) +{ + // Load DnsQuery_UTF8 and DnsRecordListFree on demand. + static volatile bool triedResolve = false; + if (!triedResolve) { + QMutexLocker locker(&local_dns_mutex); + if (!triedResolve) { + resolveLibrary(); + triedResolve = true; + } + } + + // If DnsQuery_UTF8 or DnsRecordListFree is missing, fail. + if (!local_dns_query_utf8 || !local_dns_record_list_free) { + reply->error = QDnsLookup::ResolverError, + reply->errorString = tr("Resolver functions not found"); + return; + } + + // Perform DNS query. + PDNS_RECORD dns_records; + const DNS_STATUS status = local_dns_query_utf8(requestName, requestType, DNS_QUERY_STANDARD, NULL, &dns_records, NULL); + switch (status) { + case ERROR_SUCCESS: + break; + case DNS_ERROR_RCODE_FORMAT_ERROR: + reply->error = QDnsLookup::InvalidRequestError; + reply->errorString = tr("Server could not process query"); + return; + case DNS_ERROR_RCODE_SERVER_FAILURE: + reply->error = QDnsLookup::ServerFailureError; + reply->errorString = tr("Server failure"); + return; + case DNS_ERROR_RCODE_NAME_ERROR: + reply->error = QDnsLookup::NotFoundError; + reply->errorString = tr("Non existent domain"); + return; + case DNS_ERROR_RCODE_REFUSED: + reply->error = QDnsLookup::ServerRefusedError; + reply->errorString = tr("Server refused to answer"); + return; + default: + reply->error = QDnsLookup::InvalidReplyError; + reply->errorString = tr("Invalid reply received"); + return; + } + + // Extract results. + for (PDNS_RECORD ptr = dns_records; ptr != NULL; ptr = ptr->pNext) { + const QString name = QUrl::fromAce((char*)ptr->pName); + if (ptr->wType == QDnsLookup::A) { + QDnsHostAddressRecord record; + record.d->name = name; + record.d->timeToLive = ptr->dwTtl; + record.d->value = QHostAddress(ntohl(ptr->Data.A.IpAddress)); + reply->hostAddressRecords.append(record); + } else if (ptr->wType == QDnsLookup::AAAA) { + Q_IPV6ADDR addr; + memcpy(&addr, &ptr->Data.AAAA.Ip6Address, sizeof(Q_IPV6ADDR)); + + QDnsHostAddressRecord record; + record.d->name = name; + record.d->timeToLive = ptr->dwTtl; + record.d->value = QHostAddress(addr); + reply->hostAddressRecords.append(record); + } else if (ptr->wType == QDnsLookup::CNAME) { + QDnsDomainNameRecord record; + record.d->name = name; + record.d->timeToLive = ptr->dwTtl; + record.d->value = QUrl::fromAce((char*)ptr->Data.Cname.pNameHost); + reply->canonicalNameRecords.append(record); + } else if (ptr->wType == QDnsLookup::MX) { + QDnsMailExchangeRecord record; + record.d->name = name; + record.d->exchange = QUrl::fromAce((char*)ptr->Data.Mx.pNameExchange); + record.d->preference = ptr->Data.Mx.wPreference; + record.d->timeToLive = ptr->dwTtl; + reply->mailExchangeRecords.append(record); + } else if (ptr->wType == QDnsLookup::NS) { + QDnsDomainNameRecord record; + record.d->name = name; + record.d->timeToLive = ptr->dwTtl; + record.d->value = QUrl::fromAce((char*)ptr->Data.Ns.pNameHost); + reply->nameServerRecords.append(record); + } else if (ptr->wType == QDnsLookup::PTR) { + QDnsDomainNameRecord record; + record.d->name = name; + record.d->timeToLive = ptr->dwTtl; + record.d->value = QUrl::fromAce((char*)ptr->Data.Ptr.pNameHost); + reply->pointerRecords.append(record); + } else if (ptr->wType == QDnsLookup::SRV) { + QDnsServiceRecord record; + record.d->name = name; + record.d->target = QUrl::fromAce((char*)ptr->Data.Srv.pNameTarget); + record.d->port = ptr->Data.Srv.wPort; + record.d->priority = ptr->Data.Srv.wPriority; + record.d->timeToLive = ptr->dwTtl; + record.d->weight = ptr->Data.Srv.wWeight; + reply->serviceRecords.append(record); + } else if (ptr->wType == QDnsLookup::TXT) { + QDnsTextRecord record; + record.d->name = name; + record.d->timeToLive = ptr->dwTtl; + for (unsigned int i = 0; i < ptr->Data.Txt.dwStringCount; ++i) { + record.d->values << QByteArray((char*)ptr->Data.Txt.pStringArray[i]); + } + reply->textRecords.append(record); + } + } + + local_dns_record_list_free(dns_records, DnsFreeRecordList); +} + +QT_END_NAMESPACE diff --git a/src/qdnslookup.cpp b/src/qdnslookup.cpp deleted file mode 100644 index 7b1e7c8f..00000000 --- a/src/qdnslookup.cpp +++ /dev/null @@ -1,989 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Jeremy Lainé -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdnslookup.h" -#include "qdnslookup_p.h" - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool); -Q_GLOBAL_STATIC(QThreadStorage, theDnsLookupSeedStorage); - -static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2) -{ - // Lower numbers are more preferred than higher ones. - return r1.preference() < r2.preference(); -} - -/*! - Sorts a list of QDnsMailExchangeRecord objects according to RFC 5321. -*/ - -static void qt_qdnsmailexchangerecord_sort(QList &records) -{ - // If we have no more than one result, we are done. - if (records.size() <= 1) - return; - - // Order the records by preference. - qSort(records.begin(), records.end(), qt_qdnsmailexchangerecord_less_than); - - int i = 0; - while (i < records.size()) { - - // Determine the slice of records with the current preference. - QList slice; - const quint16 slicePreference = records[i].preference(); - for (int j = i; j < records.size(); ++j) { - if (records[j].preference() != slicePreference) - break; - slice << records[j]; - } - - // Randomize the slice of records. - while (!slice.isEmpty()) { - const unsigned int pos = qrand() % slice.size(); - records[i++] = slice.takeAt(pos); - } - } -} - -static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QDnsServiceRecord &r2) -{ - // Order by priority, or if the priorities are equal, - // put zero weight records first. - return r1.priority() < r2.priority() - || (r1.priority() == r2.priority() - && r1.weight() == 0 && r2.weight() > 0); -} - -/*! - Sorts a list of QDnsServiceRecord objects according to RFC 2782. -*/ - -static void qt_qdnsservicerecord_sort(QList &records) -{ - // If we have no more than one result, we are done. - if (records.size() <= 1) - return; - - // Order the records by priority, and for records with an equal - // priority, put records with a zero weight first. - qSort(records.begin(), records.end(), qt_qdnsservicerecord_less_than); - - int i = 0; - while (i < records.size()) { - - // Determine the slice of records with the current priority. - QList slice; - const quint16 slicePriority = records[i].priority(); - unsigned int sliceWeight = 0; - for (int j = i; j < records.size(); ++j) { - if (records[j].priority() != slicePriority) - break; - sliceWeight += records[j].weight(); - slice << records[j]; - } -#ifdef QDNSLOOKUP_DEBUG - qDebug("qt_qdnsservicerecord_sort() : priority %i (size: %i, total weight: %i)", - slicePriority, slice.size(), sliceWeight); -#endif - - // Order the slice of records. - while (!slice.isEmpty()) { - const unsigned int weightThreshold = qrand() % (sliceWeight + 1); - unsigned int summedWeight = 0; - for (int j = 0; j < slice.size(); ++j) { - summedWeight += slice[j].weight(); - if (summedWeight >= weightThreshold) { -#ifdef QDNSLOOKUP_DEBUG - qDebug("qt_qdnsservicerecord_sort() : adding %s %i (weight: %i)", - qPrintable(slice[j].target()), slice[j].port(), - slice[j].weight()); -#endif - // Adjust the slice weight and take the current record. - sliceWeight -= slice[j].weight(); - records[i++] = slice.takeAt(j); - break; - } - } - } - } -} - -/*! - \class QDnsLookup - \brief The QDnsLookup class represents a DNS lookup. - - \inmodule QtNetwork - \ingroup network - - QDnsLookup uses the mechanisms provided by the operating system to perform - DNS lookups. To perform a lookup you need to specify a \l name and \l type - then invoke the \l{QDnsLookup::lookup()}{lookup()} slot. The - \l{QDnsLookup::finished()}{finished()} signal will be emitted upon - completion. - - For example, you can determine which servers an XMPP chat client should - connect to for a given domain with: - - \snippet doc/src/snippets/code/src_network_kernel_qdnslookup.cpp 0 - - Once the request finishes you can handle the results with: - - \snippet doc/src/snippets/code/src_network_kernel_qdnslookup.cpp 1 - - \note If you simply want to find the IP address(es) associated with a host - name, or the host name associated with an IP address you should use - QHostInfo instead. -*/ - -/*! - \enum QDnsLookup::Error - - Indicates all possible error conditions found during the - processing of the DNS lookup. - - \value NoError no error condition. - - \value ResolverError there was an error initializing the system's - DNS resolver. - - \value OperationCancelledError the lookup was aborted using the abort() - method. - - \value InvalidRequestError the requested DNS lookup was invalid. - - \value InvalidReplyError the reply returned by the server was invalid. - - \value ServerFailureError the server encountered an internal failure - while processing the request (SERVFAIL). - - \value ServerRefusedError the server refused to process the request for - security or policy reasons (REFUSED). - - \value NotFoundError the requested domain name does not exist - (NXDOMAIN). -*/ - -/*! - \enum QDnsLookup::Type - - Indicates the type of DNS lookup that was performed. - - \value A IPv4 address records. - - \value AAAA IPv6 address records. - - \value ANY any records. - - \value CNAME canonical name records. - - \value MX mail exchange records. - - \value NS name server records. - - \value PTR pointer records. - - \value SRV service records. - - \value TXT text records. -*/ - -/*! - \fn void QDnsLookup::finished() - - This signal is emitted when the reply has finished processing. -*/ - -/*! - \fn void QDnsLookup::nameChanged(const QString &name) - - This signal is emitted when the lookup \l name changes. - \a name is the new lookup name. -*/ - -/*! - \fn void QDnsLookup::typeChanged(Type type) - - This signal is emitted when the lookup \l type changes. - \a type is the new lookup type. -*/ - -/*! - Constructs a QDnsLookup object and sets \a parent as the parent object. - - The \l type property will default to QDnsLookup::A. -*/ - -QDnsLookup::QDnsLookup(QObject *parent) - : QObject(parent) - , d_ptr(new QDnsLookupPrivate(this)) -{ - qRegisterMetaType(); -} -/*! - Constructs a QDnsLookup object for the given \a type and \a name and sets - \a parent as the parent object. -*/ - -QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent) - : QObject(parent) - , d_ptr(new QDnsLookupPrivate(this)) -{ - Q_D(QDnsLookup); - qRegisterMetaType(); - d->name = name; - d->type = type; -} - -/*! - Destroys the QDnsLookup object. - - It is safe to delete a QDnsLookup object even if it is not finished, you - will simply never receive its results. -*/ - -QDnsLookup::~QDnsLookup() -{ -} - -/*! - \property QDnsLookup::error - \brief the type of error that occurred if the DNS lookup failed, or NoError. -*/ - -QDnsLookup::Error QDnsLookup::error() const -{ - return d_func()->reply.error; -} - -/*! - \property QDnsLookup::errorString - \brief a human-readable description of the error if the DNS lookup failed. -*/ - -QString QDnsLookup::errorString() const -{ - return d_func()->reply.errorString; -} - -/*! - \property QDnsLookup::finished - \brief whether the reply has finished or was aborted. -*/ - -bool QDnsLookup::isFinished() const -{ - return d_func()->isFinished; -} - -/*! - \property QDnsLookup::name - \brief the name to lookup. - - \note The name will be encoded using IDNA, which means it's unsuitable for - querying SRV records compatible with the DNS-SD specification. -*/ - -QString QDnsLookup::name() const -{ - return d_func()->name; -} - -void QDnsLookup::setName(const QString &name) -{ - Q_D(QDnsLookup); - if (name != d->name) { - d->name = name; - emit nameChanged(name); - } -} - -/*! - \property QDnsLookup::type - \brief the type of DNS lookup. -*/ - -QDnsLookup::Type QDnsLookup::type() const -{ - return d_func()->type; -} - -void QDnsLookup::setType(Type type) -{ - Q_D(QDnsLookup); - if (type != d->type) { - d->type = type; - emit typeChanged(type); - } -} - -/*! - Returns the list of canonical name records associated with this lookup. -*/ - -QList QDnsLookup::canonicalNameRecords() const -{ - return d_func()->reply.canonicalNameRecords; -} - -/*! - Returns the list of host address records associated with this lookup. -*/ - -QList QDnsLookup::hostAddressRecords() const -{ - return d_func()->reply.hostAddressRecords; -} - -/*! - Returns the list of mail exchange records associated with this lookup. - - The records are sorted according to - \l{http://www.rfc-editor.org/rfc/rfc5321.txt}{RFC 5321}, so if you use them - to connect to servers, you should try them in the order they are listed. -*/ - -QList QDnsLookup::mailExchangeRecords() const -{ - return d_func()->reply.mailExchangeRecords; -} - -/*! - Returns the list of name server records associated with this lookup. -*/ - -QList QDnsLookup::nameServerRecords() const -{ - return d_func()->reply.nameServerRecords; -} - -/*! - Returns the list of pointer records associated with this lookup. -*/ - -QList QDnsLookup::pointerRecords() const -{ - return d_func()->reply.pointerRecords; -} - -/*! - Returns the list of service records associated with this lookup. - - The records are sorted according to - \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}, so if you use them - to connect to servers, you should try them in the order they are listed. -*/ - -QList QDnsLookup::serviceRecords() const -{ - return d_func()->reply.serviceRecords; -} - -/*! - Returns the list of text records associated with this lookup. -*/ - -QList QDnsLookup::textRecords() const -{ - return d_func()->reply.textRecords; -} - -/*! - Aborts the DNS lookup operation. - - If the lookup is already finished, does nothing. -*/ - -void QDnsLookup::abort() -{ - Q_D(QDnsLookup); - if (d->runnable) { - d->runnable = 0; - d->reply = QDnsLookupReply(); - d->reply.error = QDnsLookup::OperationCancelledError; - d->reply.errorString = tr("Operation cancelled"); - d->isFinished = true; - emit finished(); - } -} - -/*! - Performs the DNS lookup. - - The \l{QDnsLookup::finished()}{finished()} signal is emitted upon completion. -*/ - -void QDnsLookup::lookup() -{ - Q_D(QDnsLookup); - d->isFinished = false; - d->reply = QDnsLookupReply(); - d->runnable = new QDnsLookupRunnable(d->type, QUrl::toAce(d->name)); - connect(d->runnable, SIGNAL(finished(QDnsLookupReply)), - this, SLOT(_q_lookupFinished(QDnsLookupReply)), - Qt::BlockingQueuedConnection); - theDnsLookupThreadPool()->start(d->runnable); -} - -/*! - \class QDnsDomainNameRecord - \brief The QDnsDomainNameRecord class stores information about a domain - name record. - - \inmodule QtNetwork - \ingroup network - - When performing a name server lookup, zero or more records will be returned. - Each record is represented by a QDnsDomainNameRecord instance. - - \sa QDnsLookup -*/ - -/*! - Constructs an empty domain name record object. -*/ - -QDnsDomainNameRecord::QDnsDomainNameRecord() - : d(new QDnsDomainNameRecordPrivate) -{ -} - -/*! - Constructs a copy of \a other. -*/ - -QDnsDomainNameRecord::QDnsDomainNameRecord(const QDnsDomainNameRecord &other) - : d(other.d) -{ -} - -/*! - Destroys a domain name record. -*/ - -QDnsDomainNameRecord::~QDnsDomainNameRecord() -{ -} - -/*! - Returns the name for this record. -*/ - -QString QDnsDomainNameRecord::name() const -{ - return d->name; -} - -/*! - Returns the duration in seconds for which this record is valid. -*/ - -quint32 QDnsDomainNameRecord::timeToLive() const -{ - return d->timeToLive; -} - -/*! - Returns the value for this domain name record. -*/ - -QString QDnsDomainNameRecord::value() const -{ - return d->value; -} - -/*! - Assigns the data of the \a other object to this record object, - and returns a reference to it. -*/ - -QDnsDomainNameRecord &QDnsDomainNameRecord::operator=(const QDnsDomainNameRecord &other) -{ - d = other.d; - return *this; -} - -/*! - \class QDnsHostAddressRecord - \brief The QDnsHostAddressRecord class stores information about a host - address record. - - \inmodule QtNetwork - \ingroup network - - When performing an address lookup, zero or more records will be - returned. Each record is represented by a QDnsHostAddressRecord instance. - - \sa QDnsLookup -*/ - -/*! - Constructs an empty host address record object. -*/ - -QDnsHostAddressRecord::QDnsHostAddressRecord() - : d(new QDnsHostAddressRecordPrivate) -{ -} - -/*! - Constructs a copy of \a other. -*/ - -QDnsHostAddressRecord::QDnsHostAddressRecord(const QDnsHostAddressRecord &other) - : d(other.d) -{ -} - -/*! - Destroys a host address record. -*/ - -QDnsHostAddressRecord::~QDnsHostAddressRecord() -{ -} - -/*! - Returns the name for this record. -*/ - -QString QDnsHostAddressRecord::name() const -{ - return d->name; -} - -/*! - Returns the duration in seconds for which this record is valid. -*/ - -quint32 QDnsHostAddressRecord::timeToLive() const -{ - return d->timeToLive; -} - -/*! - Returns the value for this host address record. -*/ - -QHostAddress QDnsHostAddressRecord::value() const -{ - return d->value; -} - -/*! - Assigns the data of the \a other object to this record object, - and returns a reference to it. -*/ - -QDnsHostAddressRecord &QDnsHostAddressRecord::operator=(const QDnsHostAddressRecord &other) -{ - d = other.d; - return *this; -} - -/*! - \class QDnsMailExchangeRecord - \brief The QDnsMailExchangeRecord class stores information about a DNS MX record. - - \inmodule QtNetwork - \ingroup network - - When performing a lookup on a service, zero or more records will be - returned. Each record is represented by a QDnsMailExchangeRecord instance. - - The meaning of the fields is defined in - \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}. - - \sa QDnsLookup -*/ - -/*! - Constructs an empty mail exchange record object. -*/ - -QDnsMailExchangeRecord::QDnsMailExchangeRecord() - : d(new QDnsMailExchangeRecordPrivate) -{ -} - -/*! - Constructs a copy of \a other. -*/ - -QDnsMailExchangeRecord::QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other) - : d(other.d) -{ -} - -/*! - Destroys a mail exchange record. -*/ - -QDnsMailExchangeRecord::~QDnsMailExchangeRecord() -{ -} - -/*! - Returns the domain name of the mail exchange for this record. -*/ - -QString QDnsMailExchangeRecord::exchange() const -{ - return d->exchange; -} - -/*! - Returns the name for this record. -*/ - -QString QDnsMailExchangeRecord::name() const -{ - return d->name; -} - -/*! - Returns the preference for this record. -*/ - -quint16 QDnsMailExchangeRecord::preference() const -{ - return d->preference; -} - -/*! - Returns the duration in seconds for which this record is valid. -*/ - -quint32 QDnsMailExchangeRecord::timeToLive() const -{ - return d->timeToLive; -} - -/*! - Assigns the data of the \a other object to this record object, - and returns a reference to it. -*/ - -QDnsMailExchangeRecord &QDnsMailExchangeRecord::operator=(const QDnsMailExchangeRecord &other) -{ - d = other.d; - return *this; -} - -/*! - \class QDnsServiceRecord - \brief The QDnsServiceRecord class stores information about a DNS SRV record. - - \inmodule QtNetwork - \ingroup network - - When performing a lookup on a service, zero or more records will be - returned. Each record is represented by a QDnsServiceRecord instance. - - The meaning of the fields is defined in - \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}. - - \sa QDnsLookup -*/ - -/*! - Constructs an empty service record object. -*/ - -QDnsServiceRecord::QDnsServiceRecord() - : d(new QDnsServiceRecordPrivate) -{ -} - -/*! - Constructs a copy of \a other. -*/ - -QDnsServiceRecord::QDnsServiceRecord(const QDnsServiceRecord &other) - : d(other.d) -{ -} - -/*! - Destroys a service record. -*/ - -QDnsServiceRecord::~QDnsServiceRecord() -{ -} - -/*! - Returns the name for this record. -*/ - -QString QDnsServiceRecord::name() const -{ - return d->name; -} - -/*! - Returns the port on the target host for this service record. -*/ - -quint16 QDnsServiceRecord::port() const -{ - return d->port; -} - -/*! - Returns the priority for this service record. - - A client must attempt to contact the target host with the lowest-numbered - priority. -*/ - -quint16 QDnsServiceRecord::priority() const -{ - return d->priority; -} - -/*! - Returns the domain name of the target host for this service record. -*/ - -QString QDnsServiceRecord::target() const -{ - return d->target; -} - -/*! - Returns the duration in seconds for which this record is valid. -*/ - -quint32 QDnsServiceRecord::timeToLive() const -{ - return d->timeToLive; -} - -/*! - Returns the weight for this service record. - - The weight field specifies a relative weight for entries with the same - priority. Entries with higher weights should be selected with a higher - probability. -*/ - -quint16 QDnsServiceRecord::weight() const -{ - return d->weight; -} - -/*! - Assigns the data of the \a other object to this record object, - and returns a reference to it. -*/ - -QDnsServiceRecord &QDnsServiceRecord::operator=(const QDnsServiceRecord &other) -{ - d = other.d; - return *this; -} - -/*! - \class QDnsTextRecord - \brief The QDnsTextRecord class stores information about a DNS TXT record. - - \inmodule QtNetwork - \ingroup network - - When performing a text lookup, zero or more records will be - returned. Each record is represented by a QDnsTextRecord instance. - - The meaning of the fields is defined in - \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}. - - \sa QDnsLookup -*/ - -/*! - Constructs an empty text record object. -*/ - -QDnsTextRecord::QDnsTextRecord() - : d(new QDnsTextRecordPrivate) -{ -} - -/*! - Constructs a copy of \a other. -*/ - -QDnsTextRecord::QDnsTextRecord(const QDnsTextRecord &other) - : d(other.d) -{ -} - -/*! - Destroys a text record. -*/ - -QDnsTextRecord::~QDnsTextRecord() -{ -} - -/*! - Returns the name for this text record. -*/ - -QString QDnsTextRecord::name() const -{ - return d->name; -} - -/*! - Returns the duration in seconds for which this record is valid. -*/ - -quint32 QDnsTextRecord::timeToLive() const -{ - return d->timeToLive; -} - -/*! - Returns the values for this text record. -*/ - -QList QDnsTextRecord::values() const -{ - return d->values; -} - -/*! - Assigns the data of the \a other object to this record object, - and returns a reference to it. -*/ - -QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other) -{ - d = other.d; - return *this; -} - -void QDnsLookupPrivate::_q_lookupFinished(const QDnsLookupReply &_reply) -{ - Q_Q(QDnsLookup); - if (runnable == q->sender()) { -#ifdef QDNSLOOKUP_DEBUG - qDebug("DNS reply for %s: %i (%s)", qPrintable(name), _reply.error, qPrintable(_reply.errorString)); -#endif - reply = _reply; - runnable = 0; - isFinished = true; - emit q->finished(); - } -} - -void QDnsLookupRunnable::run() -{ - QDnsLookupReply reply; - - // Validate input. - if (requestName.isEmpty()) { - reply.error = QDnsLookup::InvalidRequestError; - reply.errorString = tr("Invalid domain name"); - emit finished(reply); - return; - } - - // Perform request. - query(requestType, requestName, &reply); - - // Sort results. - if (!theDnsLookupSeedStorage()->hasLocalData()) { - qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) ^ reinterpret_cast(this)); - theDnsLookupSeedStorage()->setLocalData(new bool(true)); - } - qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords); - qt_qdnsservicerecord_sort(reply.serviceRecords); - - emit finished(reply); -} - -QDnsLookupThreadPool::QDnsLookupThreadPool() - : signalsConnected(false) -{ - // Run up to 5 lookups in parallel. - setMaxThreadCount(5); -} - -void QDnsLookupThreadPool::start(QRunnable *runnable) -{ - // Ensure threads complete at application destruction. - if (!signalsConnected) { - QMutexLocker signalsLocker(&signalsMutex); - if (!signalsConnected) { - QCoreApplication *app = QCoreApplication::instance(); - if (!app) { - qWarning("QDnsLookup requires a QCoreApplication"); - delete runnable; - return; - } - - moveToThread(app->thread()); - connect(app, SIGNAL(destroyed()), - SLOT(_q_applicationDestroyed()), Qt::DirectConnection); - signalsConnected = true; - } - } - - QThreadPool::start(runnable); -} - -void QDnsLookupThreadPool::_q_applicationDestroyed() -{ - waitForDone(); - signalsConnected = false; -} - -QT_END_NAMESPACE diff --git a/src/qdnslookup.h b/src/qdnslookup.h deleted file mode 100644 index 6f913896..00000000 --- a/src/qdnslookup.h +++ /dev/null @@ -1,238 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Jeremy Lainé -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDNSLOOKUP_H -#define QDNSLOOKUP_H - -#include -#include -#include -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Network) - -class QHostAddress; -class QDnsLookupPrivate; -class QDnsDomainNameRecordPrivate; -class QDnsHostAddressRecordPrivate; -class QDnsMailExchangeRecordPrivate; -class QDnsServiceRecordPrivate; -class QDnsTextRecordPrivate; - -class QDnsDomainNameRecord -{ -public: - QDnsDomainNameRecord(); - QDnsDomainNameRecord(const QDnsDomainNameRecord &other); - ~QDnsDomainNameRecord(); - - QString name() const; - quint32 timeToLive() const; - QString value() const; - - QDnsDomainNameRecord &operator=(const QDnsDomainNameRecord &other); - -private: - QSharedDataPointer d; - friend class QDnsLookupRunnable; -}; - -class QDnsHostAddressRecord -{ -public: - QDnsHostAddressRecord(); - QDnsHostAddressRecord(const QDnsHostAddressRecord &other); - ~QDnsHostAddressRecord(); - - QString name() const; - quint32 timeToLive() const; - QHostAddress value() const; - - QDnsHostAddressRecord &operator=(const QDnsHostAddressRecord &other); - -private: - QSharedDataPointer d; - friend class QDnsLookupRunnable; -}; - -class QDnsMailExchangeRecord -{ -public: - QDnsMailExchangeRecord(); - QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other); - ~QDnsMailExchangeRecord(); - - QString exchange() const; - QString name() const; - quint16 preference() const; - quint32 timeToLive() const; - - QDnsMailExchangeRecord &operator=(const QDnsMailExchangeRecord &other); - -private: - QSharedDataPointer d; - friend class QDnsLookupRunnable; -}; - -class QDnsServiceRecord -{ -public: - QDnsServiceRecord(); - QDnsServiceRecord(const QDnsServiceRecord &other); - ~QDnsServiceRecord(); - - QString name() const; - quint16 port() const; - quint16 priority() const; - QString target() const; - quint32 timeToLive() const; - quint16 weight() const; - - QDnsServiceRecord &operator=(const QDnsServiceRecord &other); - -private: - QSharedDataPointer d; - friend class QDnsLookupRunnable; -}; - -class QDnsTextRecord -{ -public: - QDnsTextRecord(); - QDnsTextRecord(const QDnsTextRecord &other); - ~QDnsTextRecord(); - - QString name() const; - quint32 timeToLive() const; - QList values() const; - - QDnsTextRecord &operator=(const QDnsTextRecord &other); - -private: - QSharedDataPointer d; - friend class QDnsLookupRunnable; -}; - -class QDnsLookup : public QObject -{ - Q_OBJECT - Q_ENUMS(Error Type) - Q_PROPERTY(Error error READ error NOTIFY finished) - Q_PROPERTY(QString errorString READ errorString NOTIFY finished) - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - Q_PROPERTY(Type type READ type WRITE setType NOTIFY typeChanged) - -public: - enum Error - { - NoError = 0, - ResolverError, - OperationCancelledError, - InvalidRequestError, - InvalidReplyError, - ServerFailureError, - ServerRefusedError, - NotFoundError - }; - - enum Type - { - A = 1, - AAAA = 28, - ANY = 255, - CNAME = 5, - MX = 15, - NS = 2, - PTR = 12, - SRV = 33, - TXT = 16 - }; - - QDnsLookup(QObject *parent = 0); - QDnsLookup(Type type, const QString &name, QObject *parent = 0); - ~QDnsLookup(); - - Error error() const; - QString errorString() const; - bool isFinished() const; - - QString name() const; - void setName(const QString &name); - - Type type() const; - void setType(QDnsLookup::Type); - - QList canonicalNameRecords() const; - QList hostAddressRecords() const; - QList mailExchangeRecords() const; - QList nameServerRecords() const; - QList pointerRecords() const; - QList serviceRecords() const; - QList textRecords() const; - - -public Q_SLOTS: - void abort(); - void lookup(); - -Q_SIGNALS: - void finished(); - void nameChanged(const QString &name); - void typeChanged(Type type); - -private: - QDnsLookupPrivate *d_ptr; - Q_DECLARE_PRIVATE(QDnsLookup) - Q_PRIVATE_SLOT(d_func(), void _q_lookupFinished(const QDnsLookupReply &reply)) -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#include "qdnslookup_p.h" - -#endif // QDNSLOOKUP_H diff --git a/src/qdnslookup_p.h b/src/qdnslookup_p.h deleted file mode 100644 index 4797f345..00000000 --- a/src/qdnslookup_p.h +++ /dev/null @@ -1,216 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Jeremy Lainé -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDNSLOOKUP_P_H -#define QDNSLOOKUP_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the QDnsLookup class. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include -#include -#include -#include - -#include "qdnslookup.h" - -QT_BEGIN_NAMESPACE - -//#define QDNSLOOKUP_DEBUG - -class QDnsLookupRunnable; - -class QDnsLookupReply -{ -public: - QDnsLookupReply() - : error(QDnsLookup::NoError) - { } - - QDnsLookup::Error error; - QString errorString; - - QList canonicalNameRecords; - QList hostAddressRecords; - QList mailExchangeRecords; - QList nameServerRecords; - QList pointerRecords; - QList serviceRecords; - QList textRecords; -}; - -class QDnsLookupPrivate -{ -public: - QDnsLookupPrivate(QDnsLookup *qq) - : isFinished(false) - , type(QDnsLookup::A) - , runnable(0) - , q_ptr(qq) - { } - - void _q_lookupFinished(const QDnsLookupReply &reply); - - bool isFinished; - QString name; - QDnsLookup::Type type; - QDnsLookupReply reply; - QDnsLookupRunnable *runnable; - QDnsLookup *q_ptr; - - Q_DECLARE_PUBLIC(QDnsLookup) -}; - -class QDnsLookupRunnable : public QObject, public QRunnable -{ - Q_OBJECT - -public: - QDnsLookupRunnable(QDnsLookup::Type type, const QByteArray &name) - : requestType(type) - , requestName(name) - { } - void run(); - -signals: - void finished(const QDnsLookupReply &reply); - -private: - static void query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply); - QDnsLookup::Type requestType; - QByteArray requestName; -}; - -class QDnsLookupThreadPool : public QThreadPool -{ - Q_OBJECT - -public: - QDnsLookupThreadPool(); - void start(QRunnable *runnable); - -private slots: - void _q_applicationDestroyed(); - -private: - QMutex signalsMutex; - bool signalsConnected; -}; - -class QDnsRecordPrivate : public QSharedData -{ -public: - QDnsRecordPrivate() - : timeToLive(0) - { } - - QString name; - quint32 timeToLive; -}; - -class QDnsDomainNameRecordPrivate : public QDnsRecordPrivate -{ -public: - QDnsDomainNameRecordPrivate() - { } - - QString value; -}; - -class QDnsHostAddressRecordPrivate : public QDnsRecordPrivate -{ -public: - QDnsHostAddressRecordPrivate() - { } - - QHostAddress value; -}; - -class QDnsMailExchangeRecordPrivate : public QDnsRecordPrivate -{ -public: - QDnsMailExchangeRecordPrivate() - : preference(0) - { } - - QString exchange; - quint16 preference; -}; - -class QDnsServiceRecordPrivate : public QDnsRecordPrivate -{ -public: - QDnsServiceRecordPrivate() - : port(0), - priority(0), - weight(0) - { } - - QString target; - quint16 port; - quint16 priority; - quint16 weight; -}; - -class QDnsTextRecordPrivate : public QDnsRecordPrivate -{ -public: - QDnsTextRecordPrivate() - { } - - QList values; -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(QDnsLookupReply) - -#endif // QDNSLOOKUP_P_H diff --git a/src/qdnslookup_stub.cpp b/src/qdnslookup_stub.cpp deleted file mode 100644 index df9ed349..00000000 --- a/src/qdnslookup_stub.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Jeremy Lainé -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdnslookup_p.h" - -QT_BEGIN_NAMESPACE - -void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply) -{ - Q_UNUSED(requestType); - Q_UNUSED(requestName); - reply->error = QDnsLookup::ResolverError; - reply->errorString = QLatin1String("QDnsLookup is not implemented for this platform"); -} - -QT_END_NAMESPACE diff --git a/src/qdnslookup_symbian.cpp b/src/qdnslookup_symbian.cpp deleted file mode 100644 index bed5278e..00000000 --- a/src/qdnslookup_symbian.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Jeremy Lainé -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdnslookup_p.h" - -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply) -{ - RHostResolver dnsResolver; - RSocketServ dnsSocket; - - // Initialise resolver. - TInt err = dnsSocket.Connect(); - err = dnsResolver.Open(dnsSocket, KAfInet, KProtocolInetUdp); - if (err != KErrNone) { - reply->error = QDnsLookup::ResolverError; - reply->errorString = QLatin1String("RHostResolver::Open failed"); - return; - } - - // Perform DNS query. - TDnsQueryBuf dnsQuery; - TDnsRespSRVBuf dnsResponse; - dnsQuery().SetClass(KDnsRRClassIN); - TPtrC8 queryPtr(reinterpret_cast(requestName.constData()), requestName.size()); - dnsQuery().SetData(queryPtr); - dnsQuery().SetType(requestType); - err = dnsResolver.Query(dnsQuery, dnsResponse); - if (err != KErrNone) { - reply->error = QDnsLookup::NotFoundError; - reply->errorString = QLatin1String("RHostResolver::Query failed"); - return; - } - - // Extract results. - while (err == KErrNone) { - const QByteArray aceName((const char*)dnsResponse().Target().Ptr(), - dnsResponse().Target().Length()); - - QDnsServiceRecord record; - record.d->name = QUrl::fromAce(requestName); - record.d->target = QUrl::fromAce(aceName); - record.d->port = dnsResponse().Port(); - record.d->priority = dnsResponse().Priority(); - record.d->timeToLive = dnsResponse().RRTtl(); - record.d->weight = dnsResponse().Weight(); - reply->serviceRecords.append(record); - - err = dnsResolver.QueryGetNext(dnsResponse); - } -} - -QT_END_NAMESPACE diff --git a/src/qdnslookup_unix.cpp b/src/qdnslookup_unix.cpp deleted file mode 100644 index f4d1c64c..00000000 --- a/src/qdnslookup_unix.cpp +++ /dev/null @@ -1,323 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Jeremy Lainé -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdnslookup_p.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -static QMutex local_res_mutex; -typedef int (*dn_expand_proto)(const unsigned char *, const unsigned char *, const unsigned char *, char *, int); -static dn_expand_proto local_dn_expand = 0; -typedef void (*res_nclose_proto)(res_state); -static res_nclose_proto local_res_nclose = 0; -typedef int (*res_ninit_proto)(res_state); -static res_ninit_proto local_res_ninit = 0; -typedef int (*res_nquery_proto)(res_state, const char *, int, int, unsigned char *, int); -static res_nquery_proto local_res_nquery = 0; - -// Custom deleter to close resolver state. - -struct QDnsLookupStateDeleter -{ - static inline void cleanup(struct __res_state *pointer) - { - local_res_nclose(pointer); - } -}; - -static void resolveLibrary() -{ - QLibrary lib(QLatin1String("resolv")); - if (!lib.load()) - return; - - local_dn_expand = dn_expand_proto(lib.resolve("__dn_expand")); - if (!local_dn_expand) - local_dn_expand = dn_expand_proto(lib.resolve("dn_expand")); - - local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose")); - if (!local_res_nclose) - local_res_nclose = res_nclose_proto(lib.resolve("res_9_nclose")); - if (!local_res_nclose) - local_res_nclose = res_nclose_proto(lib.resolve("res_nclose")); - - local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit")); - if (!local_res_ninit) - local_res_ninit = res_ninit_proto(lib.resolve("res_9_ninit")); - if (!local_res_ninit) - local_res_ninit = res_ninit_proto(lib.resolve("res_ninit")); - - local_res_nquery = res_nquery_proto(lib.resolve("__res_nquery")); - if (!local_res_nquery) - local_res_nquery = res_nquery_proto(lib.resolve("res_9_nquery")); - if (!local_res_nquery) - local_res_nquery = res_nquery_proto(lib.resolve("res_nquery")); -} - -void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply) -{ - // Load dn_expand, res_ninit and res_nquery on demand. - static volatile bool triedResolve = false; - if (!triedResolve) { - QMutexLocker locker(&local_res_mutex); - if (!triedResolve) { - resolveLibrary(); - triedResolve = true; - } - } - - // If dn_expand, res_ninit or res_nquery is missing, fail. - if (!local_dn_expand || !local_res_nclose || !local_res_ninit || !local_res_nquery) { - reply->error = QDnsLookup::ResolverError; - reply->errorString = tr("Resolver functions not found"); - return; - } - - // Initialize state. - struct __res_state state; - memset(&state, 0, sizeof(state)); - if (local_res_ninit(&state) < 0) { - reply->error = QDnsLookup::ResolverError; - reply->errorString = tr("Resolver initialization failed"); - return; - } -#ifdef QDNSLOOKUP_DEBUG - state.options |= RES_DEBUG; -#endif - QScopedPointer state_ptr(&state); - - // Perform DNS query. - unsigned char response[PACKETSZ]; - memset(response, 0, sizeof(response)); - const int responseLength = local_res_nquery(&state, requestName, C_IN, requestType, response, sizeof(response)); - - // Check the response header. - HEADER *header = (HEADER*)response; - const int answerCount = ntohs(header->ancount); - switch (header->rcode) { - case NOERROR: - break; - case FORMERR: - reply->error = QDnsLookup::InvalidRequestError; - reply->errorString = tr("Server could not process query"); - return; - case SERVFAIL: - reply->error = QDnsLookup::ServerFailureError; - reply->errorString = tr("Server failure"); - return; - case NXDOMAIN: - reply->error = QDnsLookup::NotFoundError; - reply->errorString = tr("Non existent domain"); - return; - case REFUSED: - reply->error = QDnsLookup::ServerRefusedError; - reply->errorString = tr("Server refused to answer"); - return; - default: - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Invalid reply received"); - return; - } - - // Check the reply is valid. - if (responseLength < int(sizeof(HEADER))) { - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Invalid reply received"); - return; - } - - // Skip the query host, type (2 bytes) and class (2 bytes). - char host[PACKETSZ], answer[PACKETSZ]; - unsigned char *p = response + sizeof(HEADER); - int status = local_dn_expand(response, response + responseLength, p, host, sizeof(host)); - if (status < 0) { - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Could not expand domain name"); - return; - } - p += status + 4; - - // Extract results. - int answerIndex = 0; - while ((p < response + responseLength) && (answerIndex < answerCount)) { - status = local_dn_expand(response, response + responseLength, p, host, sizeof(host)); - if (status < 0) { - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Could not expand domain name"); - return; - } - const QString name = QUrl::fromAce(host); - - p += status; - const quint16 type = (p[0] << 8) | p[1]; - p += 2; // RR type - p += 2; // RR class - const quint32 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; - p += 4; - const quint16 size = (p[0] << 8) | p[1]; - p += 2; - - if (type == QDnsLookup::A) { - if (size != 4) { - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Invalid IPv4 address record"); - return; - } - const quint32 addr = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; - QDnsHostAddressRecord record; - record.d->name = name; - record.d->timeToLive = ttl; - record.d->value = QHostAddress(addr); - reply->hostAddressRecords.append(record); - } else if (type == QDnsLookup::AAAA) { - if (size != 16) { - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Invalid IPv6 address record"); - return; - } - QDnsHostAddressRecord record; - record.d->name = name; - record.d->timeToLive = ttl; - record.d->value = QHostAddress(p); - reply->hostAddressRecords.append(record); - } else if (type == QDnsLookup::CNAME) { - status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer)); - if (status < 0) { - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Invalid canonical name record"); - return; - } - QDnsDomainNameRecord record; - record.d->name = name; - record.d->timeToLive = ttl; - record.d->value = QUrl::fromAce(answer); - reply->canonicalNameRecords.append(record); - } else if (type == QDnsLookup::NS) { - status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer)); - if (status < 0) { - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Invalid name server record"); - return; - } - QDnsDomainNameRecord record; - record.d->name = name; - record.d->timeToLive = ttl; - record.d->value = QUrl::fromAce(answer); - reply->nameServerRecords.append(record); - } else if (type == QDnsLookup::PTR) { - status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer)); - if (status < 0) { - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Invalid pointer record"); - return; - } - QDnsDomainNameRecord record; - record.d->name = name; - record.d->timeToLive = ttl; - record.d->value = QUrl::fromAce(answer); - reply->pointerRecords.append(record); - } else if (type == QDnsLookup::MX) { - const quint16 preference = (p[0] << 8) | p[1]; - status = local_dn_expand(response, response + responseLength, p + 2, answer, sizeof(answer)); - if (status < 0) { - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Invalid mail exchange record"); - return; - } - QDnsMailExchangeRecord record; - record.d->exchange = QUrl::fromAce(answer); - record.d->name = name; - record.d->preference = preference; - record.d->timeToLive = ttl; - reply->mailExchangeRecords.append(record); - } else if (type == QDnsLookup::SRV) { - const quint16 priority = (p[0] << 8) | p[1]; - const quint16 weight = (p[2] << 8) | p[3]; - const quint16 port = (p[4] << 8) | p[5]; - status = local_dn_expand(response, response + responseLength, p + 6, answer, sizeof(answer)); - if (status < 0) { - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Invalid service record"); - return; - } - QDnsServiceRecord record; - record.d->name = name; - record.d->target = QUrl::fromAce(answer); - record.d->port = port; - record.d->priority = priority; - record.d->timeToLive = ttl; - record.d->weight = weight; - reply->serviceRecords.append(record); - } else if (type == QDnsLookup::TXT) { - unsigned char *txt = p; - QDnsTextRecord record; - record.d->name = name; - record.d->timeToLive = ttl; - while (txt < p + size) { - const unsigned char length = *txt; - txt++; - if (txt + length > p + size) { - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Invalid text record"); - return; - } - record.d->values << QByteArray((char*)txt, length); - txt += length; - } - reply->textRecords.append(record); - } - p += size; - answerIndex++; - } -} - -QT_END_NAMESPACE diff --git a/src/qdnslookup_win.cpp b/src/qdnslookup_win.cpp deleted file mode 100644 index 87d6955a..00000000 --- a/src/qdnslookup_win.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Jeremy Lainé -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdnslookup_p.h" - -#include -#include -#include - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -static QMutex local_dns_mutex; -typedef DNS_STATUS (*dns_query_utf8_proto)(PCSTR,WORD,DWORD,PIP4_ARRAY,PDNS_RECORD*,PVOID*); -static dns_query_utf8_proto local_dns_query_utf8 = 0; -typedef void (*dns_record_list_free_proto)(PDNS_RECORD,DNS_FREE_TYPE); -static dns_record_list_free_proto local_dns_record_list_free = 0; - -static void resolveLibrary() -{ - QLibrary lib(QLatin1String("dnsapi")); - if (!lib.load()) - return; - - local_dns_query_utf8 = (dns_query_utf8_proto) lib.resolve(QLatin1String("dnsapi"), "DnsQuery_UTF8"); - local_dns_record_list_free = (dns_record_list_free_proto) lib.resolve(QLatin1String("dnsapi"), "DnsRecordListFree"); -} - -void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply) -{ - // Load DnsQuery_UTF8 and DnsRecordListFree on demand. - static volatile bool triedResolve = false; - if (!triedResolve) { - QMutexLocker locker(&local_dns_mutex); - if (!triedResolve) { - resolveLibrary(); - triedResolve = true; - } - } - - // If DnsQuery_UTF8 or DnsRecordListFree is missing, fail. - if (!local_dns_query_utf8 || !local_dns_record_list_free) { - reply->error = QDnsLookup::ResolverError, - reply->errorString = tr("Resolver functions not found"); - return; - } - - // Perform DNS query. - PDNS_RECORD dns_records; - const DNS_STATUS status = local_dns_query_utf8(requestName, requestType, DNS_QUERY_STANDARD, NULL, &dns_records, NULL); - switch (status) { - case ERROR_SUCCESS: - break; - case DNS_ERROR_RCODE_FORMAT_ERROR: - reply->error = QDnsLookup::InvalidRequestError; - reply->errorString = tr("Server could not process query"); - return; - case DNS_ERROR_RCODE_SERVER_FAILURE: - reply->error = QDnsLookup::ServerFailureError; - reply->errorString = tr("Server failure"); - return; - case DNS_ERROR_RCODE_NAME_ERROR: - reply->error = QDnsLookup::NotFoundError; - reply->errorString = tr("Non existent domain"); - return; - case DNS_ERROR_RCODE_REFUSED: - reply->error = QDnsLookup::ServerRefusedError; - reply->errorString = tr("Server refused to answer"); - return; - default: - reply->error = QDnsLookup::InvalidReplyError; - reply->errorString = tr("Invalid reply received"); - return; - } - - // Extract results. - for (PDNS_RECORD ptr = dns_records; ptr != NULL; ptr = ptr->pNext) { - const QString name = QUrl::fromAce((char*)ptr->pName); - if (ptr->wType == QDnsLookup::A) { - QDnsHostAddressRecord record; - record.d->name = name; - record.d->timeToLive = ptr->dwTtl; - record.d->value = QHostAddress(ntohl(ptr->Data.A.IpAddress)); - reply->hostAddressRecords.append(record); - } else if (ptr->wType == QDnsLookup::AAAA) { - Q_IPV6ADDR addr; - memcpy(&addr, &ptr->Data.AAAA.Ip6Address, sizeof(Q_IPV6ADDR)); - - QDnsHostAddressRecord record; - record.d->name = name; - record.d->timeToLive = ptr->dwTtl; - record.d->value = QHostAddress(addr); - reply->hostAddressRecords.append(record); - } else if (ptr->wType == QDnsLookup::CNAME) { - QDnsDomainNameRecord record; - record.d->name = name; - record.d->timeToLive = ptr->dwTtl; - record.d->value = QUrl::fromAce((char*)ptr->Data.Cname.pNameHost); - reply->canonicalNameRecords.append(record); - } else if (ptr->wType == QDnsLookup::MX) { - QDnsMailExchangeRecord record; - record.d->name = name; - record.d->exchange = QUrl::fromAce((char*)ptr->Data.Mx.pNameExchange); - record.d->preference = ptr->Data.Mx.wPreference; - record.d->timeToLive = ptr->dwTtl; - reply->mailExchangeRecords.append(record); - } else if (ptr->wType == QDnsLookup::NS) { - QDnsDomainNameRecord record; - record.d->name = name; - record.d->timeToLive = ptr->dwTtl; - record.d->value = QUrl::fromAce((char*)ptr->Data.Ns.pNameHost); - reply->nameServerRecords.append(record); - } else if (ptr->wType == QDnsLookup::PTR) { - QDnsDomainNameRecord record; - record.d->name = name; - record.d->timeToLive = ptr->dwTtl; - record.d->value = QUrl::fromAce((char*)ptr->Data.Ptr.pNameHost); - reply->pointerRecords.append(record); - } else if (ptr->wType == QDnsLookup::SRV) { - QDnsServiceRecord record; - record.d->name = name; - record.d->target = QUrl::fromAce((char*)ptr->Data.Srv.pNameTarget); - record.d->port = ptr->Data.Srv.wPort; - record.d->priority = ptr->Data.Srv.wPriority; - record.d->timeToLive = ptr->dwTtl; - record.d->weight = ptr->Data.Srv.wWeight; - reply->serviceRecords.append(record); - } else if (ptr->wType == QDnsLookup::TXT) { - QDnsTextRecord record; - record.d->name = name; - record.d->timeToLive = ptr->dwTtl; - for (unsigned int i = 0; i < ptr->Data.Txt.dwStringCount; ++i) { - record.d->values << QByteArray((char*)ptr->Data.Txt.pStringArray[i]); - } - reply->textRecords.append(record); - } - } - - local_dns_record_list_free(dns_records, DnsFreeRecordList); -} - -QT_END_NAMESPACE diff --git a/src/src.pro b/src/src.pro index b5ed68f3..db929dcb 100644 --- a/src/src.pro +++ b/src/src.pro @@ -27,92 +27,7 @@ TARGET = $$QXMPP_LIBRARY_NAME VERSION = $$QXMPP_VERSION DESTDIR = $$QXMPP_LIBRARY_DIR -# Header files -INSTALL_HEADERS = \ - QXmppArchiveIq.h \ - QXmppBindIq.h \ - QXmppBookmarkSet.h \ - QXmppByteStreamIq.h \ - QXmppCodec.h \ - QXmppConstants.h \ - QXmppDataForm.h \ - QXmppDiscoveryIq.h \ - QXmppElement.h \ - QXmppEntityTimeIq.h \ - QXmppGlobal.h \ - QXmppIbbIq.h \ - QXmppIq.h \ - QXmppJingleIq.h \ - QXmppLogger.h \ - QXmppMessage.h \ - QXmppMucIq.h \ - QXmppNonSASLAuth.h \ - QXmppPacket.h \ - QXmppPingIq.h \ - QXmppPresence.h \ - QXmppPubSubIq.h \ - QXmppRosterIq.h \ - QXmppRpcIq.h \ - QXmppRtpChannel.h \ - QXmppSaslAuth.h \ - QXmppSessionIq.h \ - QXmppSocks.h \ - QXmppStanza.h \ - QXmppStream.h \ - QXmppStreamFeatures.h \ - QXmppStreamInitiationIq.h \ - QXmppStun.h \ - QXmppUtils.h \ - QXmppVCardIq.h \ - QXmppVersionIq.h - -# Source files -SOURCES += \ - QXmppArchiveIq.cpp \ - QXmppBindIq.cpp \ - QXmppBookmarkSet.cpp \ - QXmppByteStreamIq.cpp \ - QXmppCodec.cpp \ - QXmppConstants.cpp \ - QXmppDataForm.cpp \ - QXmppDiscoveryIq.cpp \ - QXmppElement.cpp \ - QXmppEntityTimeIq.cpp \ - QXmppGlobal.cpp \ - QXmppIbbIq.cpp \ - QXmppIq.cpp \ - QXmppJingleIq.cpp \ - QXmppLogger.cpp \ - QXmppMessage.cpp \ - QXmppMucIq.cpp \ - QXmppNonSASLAuth.cpp \ - QXmppPacket.cpp \ - QXmppPingIq.cpp \ - QXmppPresence.cpp \ - QXmppPubSubIq.cpp \ - QXmppRosterIq.cpp \ - QXmppRpcIq.cpp \ - QXmppRtpChannel.cpp \ - QXmppSaslAuth.cpp \ - QXmppSessionIq.cpp \ - QXmppSocks.cpp \ - QXmppStanza.cpp \ - QXmppStream.cpp \ - QXmppStreamFeatures.cpp \ - QXmppStreamInitiationIq.cpp \ - QXmppStun.cpp \ - QXmppUtils.cpp \ - QXmppVCardIq.cpp \ - QXmppVersionIq.cpp - -# DNS -HEADERS += qdnslookup.h qdnslookup_p.h -SOURCES += qdnslookup.cpp -android:SOURCES += qdnslookup_stub.cpp -else:symbian:SOURCES += qdnslookup_symbian.cpp -else:unix:SOURCES += qdnslookup_unix.cpp -else:win32:SOURCES += qdnslookup_win.cpp - +include(base/base.pri) include(client/client.pri) include(server/server.pri) -- cgit v1.2.3