pax_global_header00006660000000000000000000000064126300625520014513gustar00rootroot0000000000000052 comment=3b444f1a1076d3a4c3cdef042b71b180bab8c4c5 qxmpp-0.9.3/000077500000000000000000000000001263006255200126715ustar00rootroot00000000000000qxmpp-0.9.3/.travis.yml000066400000000000000000000007521263006255200150060ustar00rootroot00000000000000language: cpp cache: apt env: - QT_SELECT=qt4 ; CONFIG=minimal - QT_SELECT=qt4 ; CONFIG=minimal-static - QT_SELECT=qt4 ; CONFIG=full - QT_SELECT=qt4 ; CONFIG=full-debug - QT_SELECT=qt4 ; CONFIG=full-static - QT_SELECT=qt5 ; CONFIG=minimal - QT_SELECT=qt5 ; CONFIG=minimal-static - QT_SELECT=qt5 ; CONFIG=full - QT_SELECT=qt5 ; CONFIG=full-debug - QT_SELECT=qt5 ; CONFIG=full-static install: - tests/travis/install-build-depends script: - tests/travis/build-and-test qxmpp-0.9.3/AUTHORS000066400000000000000000000005161263006255200137430ustar00rootroot00000000000000QXMPP AUTHORS ------------- Manjeet Dahiya * Initial author of QXmpp. Jeremy Lainé * Co-author of QXmpp. Ian Reinhart Geiser * Initial author of Jabber-RPC support. Georg Rudoy <0xd34df00d@gmail.com> * Author of receipts manager, extended stanza addressing. qxmpp-0.9.3/CHANGELOG000066400000000000000000000323471263006255200141140ustar00rootroot00000000000000QXmpp 0.9.3 (Dec 3, 2015) ------------------------- - Add QXmppIceConnection::gatheringState property. - Improve QXmppTransferManager::sendFile's handling of QIODevice ownership. - Fix QXmppTransferManagerFix convering filename to a QUrl. QXmpp 0.9.2 (Sep 2, 2015) ------------------------- - Fix build error for debug builds. - Allow QXmppJingleIq to have multiple contents. QXmpp 0.9.1 (Aug 30, 2015) -------------------------- - Fix build error when VPX support is enabled (issue 71). QXmpp 0.9.0 (Aug 28, 2015) -------------------------- - Fix phone numbers incorrectly read from / written to vCard as "PHONE" element instead of "TEL" (issue 65). - Make QXmppClient::connectToServer(QXmppConfiguration, QXmppPresence) a slot (issue 63). - Correctly receive data immediately following a SOCKS5 message (issue 64). - Make QXmppStream handle end of incoming stream (issue 70). - Add unit tests for QXmppCallManager and QXmppTransferManager. - Improve ICE implementation to follow RFC 5245 more closely and hide implementation details from public API. QXmpp 0.8.3 (Mar 13, 2015) -------------------------- - Add a QXmppClient::sslErrors signal to report SSL errors. - Handle broken servers which send "bad-auth" instead of "not-authorized". - Fix a compilation issue with Qt 5.5 due to a missing header include. - Do not install test cases. - Remove trailing comma after last item in enums. QXmpp 0.8.2 (Jan 7, 2015) ------------------------- - The previous release was missing an update to the VERSION definition, resulting in stale pkg-config files. This release fixes this issue. - Refactor HTML documentation so that "make docs" works in out-of-source builds. - Add support for Opus audio codec. - Enable error concealment for VPX video codec. QXmpp 0.8.1 (Dec 19, 2014) -------------------------- - Use QString() instead of "" for default methods arguments, to enable building project which use QT_NO_CAST_FROM_ASCII. - Add support for legacy SSL. - Add XEP-0333: Chat Markers attributes to QXmppMessage. - Add QXmppClient::socketErrorString to retrieve socket error string. - Add equality/inequality operators for QXmppVCardIq. - Add "make check" command to run tests. QXmpp 0.8.0 (Mar 26, 2014) -------------------------- - Fix QXmppServer incoming connections with Qt5 (issue 175). - Support for QXmppMessage extensions having tag names other than 'x'. - Support for retrieving the source QDomElement that has been used to initialize a QXmppElement. - Add organizations info interface to QXmppVCardIq. - Remove deprecated QXmppPresence::Status type. QXmpp 0.7.6 (Mar 9, 2013) ------------------------- - Add QXmppClient::insertExtension to insert an extension at a given index. - Disable Facebook / Google / Facebook specific mechanisms if we do not have the corresponding credentials. QXmpp 0.7.5 (Jan 11, 2013) -------------------------- - Replace toAscii/fromAscii with toLatin1/fromLatin1 for Qt 5 compatibility. - Fix build using clang in pedantic mode. QXmpp 0.7.4 (Oct 1, 2012) ------------------------- - Add XEP-0249: Direct MUC Invitations attributes to QXmppMessage. - Add XEP-0045: Multi-User Chat attributes to QXmppPresence. - Improve GuiClient, stop using deprecated APIs. - Improve QXmppServer: * Move statistics to a counter / gauge system. * Make it possible to call listenForClients and listenForServers multiple times to supported multiple IP address / ports. - Improve QXmppTransferManager: * Change third argument of QXmppTransferManager::sendFile to a description. * Enable file transfer using IPv6. * Allow StreamHost::host to contain a host name. QXmpp 0.7.3 (Sep 7, 2012) ------------------------- - Fix QXmppMucRoom::name(), only consider discovery IQs from the room. QXmpp 0.7.2 (Sep 6, 2012) ------------------------- - Handle Error replies in QXmppDiscoveryManager so that library users can know about errors. - If building with Qt 5, use Qt's QDnsLookup instead of our backport. - Improve MUC scriptability: * Add QXmppMucRoom::ban() to ban users. * Add QXmppMucRoom::name() to get the room's human-readable name. * Add QXmppMucRoom::participantFullJid() to lookup an occupant full JID. - With Qt >= 4.8, verify peer SSL certificate against domain name as specified by RFC 3920. - Add support for X-OAUTH2 authentication for Google Talk. - Add links to RFCs in generated HTML documentation. QXmpp 0.7.1 (Sep 3, 2012) ------------------------- - Fix export of QXmppVCardPhone class. QXmpp 0.7.0 (Sep 3, 2012) ------------------------- - New XEPs: * XEP-0033: Extended Stanza Addressing - Remove deprecated APIs: * QXmppRosterManager::rosterChanged() * QXmppConfiguration::sASLAuthMechanism() - Improve vCard support: * Add support for free-form descriptive text. * Make it possible to have several addresses. * Make it possible to have several e-mail addresses. * Make it possible to have several phone numbers. - Make it possible to set the client's extended information form (XEP-0128). - Make sure QXmppDiscoveryManager only emits results. - Fix XEP-0115 verification strings (remove duplicate features, sort form values) - Fix issues: * Issue 144: QXmppBookmarkConference autojoin parsing - Add support for see-other-host server change. - Add support for X-MESSENGER-OAUTH2 authentication for Windows Live Messenger. - Make it possible to disable non-SASL authentication. - Add QXmppClient::isAuthenticated() to query whether authentication has been performed. QXmpp 0.6.3 (Jul 24, 2012) -------------------------- - Fix regression in X-FACEBOOK-PLATFORM authentication. QXmpp 0.6.2 (Jul 22, 2012) -------------------------- - New XEPs * XEP-0071: XHTML-IM - Improve SASL code test coverage. - Improve QXmppMessage test coverage. - Add a "reason" argument to QXmppRosterManager's subscription methods. - Refactor QXmppPresence: * add availableStatusType(), priority(), statusText() * deprecate QXmppPresence::Status - Remove deprecated QXmppRosterManager::removeRosterEntry(). QXmpp 0.6.1 (Jul 20, 2012) -------------------------- - New XEPs * XEP-0221: Data Forms Media Element - Fix data form title/instructions XML serialization. - Remove confusing QXmppPresence::Status::Offline status type. - Deprecate QXmppConfiguration::setSASLAuthMechanism(), replaced by the string-based QXmppConfiguration::setSaslAuthMechanism(). - Fix issues: * Issue 111: QXmppPresence::Status::getTypeStr() gives warning if type is invisible * Issue 126: Modularize SASL mechanisms QXmpp 0.5.0 (Jul 18, 2012) -------------------------- - New XEPs * XEP-0059: Result Set Management - Build a shared library by default. - Advertise support for XEP-0249: Direct MUC Invitations - Make QXmppTransferManager fully asynchronous. - Remove QXmppPacket class. - Move utility methods to a QXmppUtils class. - Remove QXmppReconnectionManager, QXmppClient handles reconnections. - Improve QXmppArchiveManager to allow paginated navigation (Olivier Goffart). - Only emit QXmppVersionManager::versionReceived() for results. - Remove deprecated QXmppClient::discoveryIqReceived() signal. - Fix issues: * Issue 64: Compile qxmpp as shared library by default * Issue 79: Export classes for Visual C++ Compiler * Issue 140: Proper XEP-0115 ver string generation with dataforms * Issue 142: qxmpp does not build in Qt5 QXmpp 0.4.0 (Apr 12, 2012) -------------------------- - New XEPs * XEP-0048: Bookmarks * XEP-0184: Message Delivery Receipts * XEP-0224: Attention - Remove deprecated "get*" getter accessors from: QXmppClient QXmppConfiguration QXmppMessage QXmppPresence QXmppIq QXmppStanza QXmppVCardIq QXmppRosterIq - Remove deprecated headers: * QXmppRoster.h * QXmppVCard.h - Add TURN support for VoIP calls to use a relay in double-NAT network topologies. - Overhaul Multi-User Chat support to make it easier and more fully featured. - Improve QXmppServer packet routing performance. - Add support for X-FACEBOOK-PLATFORM SASL method. - Improve XEP-0136 support to enable archive deletion. - Set default keep-alive timeout to 20 seconds, enables detection of broken connections. - Make install path configurable using the PREFIX variable instead of Qt's installation path. - Make it possible to build a shared library by invoking "qmake QXMPP_LIBRARY_TYPE=lib". - Fix issues: * Issue 95: Patch for several utility methods in RosterManager * Issue 103: Does not compile for Symbian^3 with NokiaQtSDK 1.1 Beta * Issue 105: Initial presence is set before the roster request * Issue 106: QXmppClient can't override Qt's set of trusted SSL CAs * Issue 109: Patch for XEP-0224 (Attention) * Issue 113: qxmpp.pc sets incorrect include path * Issue 116: sessionStarted not set for non-SASL connections * Issue 119: ICE negotiation time out after successful ICE check * Issue 120: QXmppIceComponent doesn't accept interfaces with 255.255.255.255 netmask as a local candidate * Issue 132: [FreeBSD]: build error * Issue 135: qxmpp won't reconnect when disconnected QXmpp 0.3.0 (Mar 05, 2011) ------------------------ - New XEPs * XEP-0153: vCard-Based Avatars * XEP-0202: Entity Time - New Classes * QXmppClientExtension: base class for QXmppClient extensions (managers) * QXmppServer: base class for building XMPP servers * QXmppServerExtension: base class for QXmppServer extensions * QXmppDiscoveryManager: manager class for XEP-0030: Service Discovery * QXmppVersionManager: manager class for XEP-0092: Software Version * QXmppIceConnection: class representing an Interactive Connectivity Establishment (ICE) over UDP "connection" * QXmppRtpChannel: class representing an RTP audio channel for VoIP calls - Refactor QXmppVCardManager to use QXmppClientExtension - New Examples * example_9_vCard: vCard handling example * GuiClient: Graphical chat client, test bench for QXmpp functionalities - Deprecation * QXmppVCard class name changed to QXmppVCardIq * Signal QXmppClient::discoveryIqReceived in favour of QXmppDiscoveryManager::infoReceived and QXmppDiscoveryManager::itemsReceived - Removal Extensions QXmppArchiveManager, QXmppMucManager, QXmppCallManager, QXmppTransferManager will not load by default. Therefore following functions to provide the reference have been removed. QXmppClient::transferManager() QXmppClient::archiveManager() QXmppClient::callManager() QXmppClient::mucManager() Note: Once should use QXmppClient::addExtension() and QXmppClient::findExtension() to load or enable these extensions. - Add support for DNS SRV lookups, meaning you can connect to nearly all servers using only a JID and a password. - Improve support for SASL authentication, with a verification of the second challenge message sent by the server. - Add support for the birthday and URL attributes in vCards. - Improve STUN support for VoIP calls by detecting server-reflexive address. - Add QXMPP_VERSION and QXmppVersion() for compile and run time version checks. - Improve code documentation coverage and quality. - Remove dependency on QtGui, making it easier to write console applications. - Fix MSVC 2005 and 2008 build issues. - Fix Symbian build issues, add DNS SRV support for Symbian devices. QXmpp 0.2.0 (Aug 22, 2010) -------------------------- - New XEPs * XEP-0030: Service Discovery * XEP-0045: Multi-User Chat * XEP-0047: In-Band Bytestreams * XEP-0054: vcard-temp * XEP-0065: SOCKS5 Bytestreams * XEP-0078: Non-SASL Authentication * XEP-0082: XMPP Date and Time Profiles * XEP-0085: Chat State Notifications * XEP-0091: Legacy Delayed Delivery * XEP-0092: Software Version * XEP-0095: Stream Initiation * XEP-0096: SI File Transfer * XEP-0115: Entity Capabilities * XEP-0128: Service Discovery Extensions * XEP-0166: Jingle * XEP-0167: Jingle RTP Sessions * XEP-0199: XMPP Ping * XEP-0203: Delayed Delivery * XEP-0009: Jabber-RPC * XEP-0004: Data Forms - New XEPs (Initial Support) * XEP-0136: Message Archiving * XEP-0176: Jingle ICE-UDP Transport Method [Experimental] - New authentication schemes * DIGEST-MD5 * SASL * NonSASL * Anonymous - Add doxygen documentation - Add targets in *.pro file for packaging, installing and generating documentation - Use QXmlStreamWriter while creating stanzas to be sent to the server - Clean up getter accessors from "getFoo" to "foo" - Add proper file transfer management - Add support for keep-alive pings - Report authentication errors - Automatic reconnection mechanism - Test suite for stanza parsing/serialisation - Refactor the logging code - Add proxy support - Fixed compile time warning messages - New examples - Support for attaching an extension element to messages and presences (QXmppElement) - Move parsing to the stanzas itself QXmppStanza::parse() - QXMPP_NO_GUI define to remove dependency on QtGui - Change QXmppRoster to QXmppRosterManager to have a consistent API QXmpp 0.1 (Jun 14, 2009) ------------------------ - First public release qxmpp-0.9.3/LICENSE.LGPL000066400000000000000000000635041263006255200144430ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! qxmpp-0.9.3/README.md000066400000000000000000000110241263006255200141460ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/qxmpp-project/qxmpp.png)](https://travis-ci.org/qxmpp-project/qxmpp) ABOUT QXMPP =========== QXmpp is a cross-platform C++ XMPP client and server library. It is written in C++ and uses Qt framework. QXmpp strives to be as easy to use as possible, the underlying TCP socket, the core XMPP RFCs (RFC3920 and RFC3921) and XMPP extensions have been nicely encapsulated into classes. QXmpp comes with full API documentation, automatic tests and many examples. QXmpp uses Qt extensively, and as such users need to a have working knowledge of C++ and Qt basics (Signals and Slots and Qt data types). Qt is the only third party library which is required to build QXmpp, but libraries such as speex and theora enable additional features. QXmpp is released under the terms of the GNU Lesser General Public License, version 2.1 or later. BUILDING QXMPP ============== QXmpp requires Qt 4.5 or higher (including Qt 5.x) with SSL enabled and it uses the standard qmake build system of Qt. Build from command line: cd qmake You can pass the following arguments to qmake: PREFIX= to change the install prefix default: unix: /usr/local on unix other: $$[QT_INSTALL_PREFIX] QXMPP_AUTOTEST_INTERNAL=1 to enabled internal autotests QXMPP_LIBRARY_TYPE=staticlib to build a static version of QXmpp QXMPP_USE_DOXYGEN=1 to build the HTML documentation QXMPP_USE_OPUS=1 to enable opus audio codec QXMPP_USE_SPEEX=1 to enable speex audio codec QXMPP_USE_THEORA=1 to enable theora video codec QXMPP_USE_VPX=1 to enable vpx video codec Note: by default QXmpp is built as a shared library. If you decide to build a static library instead, you will need to pass -DQXMPP_STATIC when building your programs against QXmpp. Build using Qt Creator: Open the qxmpp.pro file in Qt Creator and hit "Build All" to build all the examples and library. INSTALLING QXMPP ================ After building QXmpp, you can install the Headers, Libraries and Documentation using the following command: Install from command line: install Path of installations: Headers: PREFIX/include/qxmpp Library: PREFIX/lib API Documentation: PREFIX/share/doc/qxmpp To link against the shared version of QXmpp, you need to add -DQXMPP_SHARED to your C++ flags. EXAMPLES ======== Look at the example directory for various examples. Here is a description of a few. * *example_0_connected* This example just connects to the xmpp server and start receiving presences (updates) from the server. After running this example, you can see this user online, if it's added in your roster (friends list). * *example_1_echoClient* This is a very simple bot which echoes the message sent to it. Run this example, send it a message from a friend of this bot and you will receive the message back. This example shows how to receive and send messages. * *GuiClient* This is a full fledged Graphical XMPP client. This example will uses most of the part of this library. DOCUMENTATION ============= You can find the API documentation for the latest QXmpp version here: http://doc.qxmpp.org/ SUPPORTED PLATFORMS =================== It should work on all the plaforms supported by Qt. For a complete list of platforms support by Qt, see: http://qt-project.org/doc/supported-platforms.html In past, we have tested on variety of platforms: win32-g++ (Qt SDK) win32-msvc2008 (Qt MSVC-2008) win64-msvc2008 (Qt MSVC-2008) symbian-gcce (Nokia Qt SDK) linux-g++ (32-bit and 64-bit) macos-g++ (32-bit and 64-bit) Please note that on Symbian, you will need to make sure your add the "NetworkServices" to your application to enable it to access the network. You can do this by adding the following to your .pro file: TARGET.CAPABILITY = "NetworkServices" HOW TO REPORT A BUG =================== If you think you have found a bug in QXmpp, we would like to hear about it so that we can fix it. Before reporting a bug, please check if the issue is already know at: https://github.com/qxmpp-project/qxmpp/issues DISCUSSION GROUP ================ Join QXmpp Discussion Group for queries, discussions and updates. http://groups.google.com/group/qxmpp qxmpp-0.9.3/doc/000077500000000000000000000000001263006255200134365ustar00rootroot00000000000000qxmpp-0.9.3/doc/doc.pro000066400000000000000000000007121263006255200147250ustar00rootroot00000000000000include(../qxmpp.pri) TEMPLATE = app CONFIG += console CONFIG -= app_bundle QT -= gui INCLUDEPATH += $$QXMPP_INCLUDEPATH TARGET = doxyfilter SOURCES += doxyfilter.cpp windows { DOXYFILTER = $${TARGET}.exe } else { DOXYFILTER = ./$${TARGET} } # Build rules docs.commands = $${DOXYFILTER} -g $${PWD} && $${DOXYFILTER} docs.depends = $${TARGET} QMAKE_CLEAN += Doxyfile doxygen_sqlite3.db unix:QMAKE_DISTCLEAN += -r html QMAKE_EXTRA_TARGETS += docs qxmpp-0.9.3/doc/doxyfilter.cpp000066400000000000000000000103601263006255200163330ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppGlobal.h" static void setField(QString &code, const QString &name, const QString &value) { code.replace( QRegExp(QString("(%1\\s*=)[^\\r\\n]*").arg(name)), QString("\\1 %1").arg(value)); } static void usage() { QTextStream output(stderr); output << "Usage:" << endl; output << " doxyfilter Generate documentation" << endl; output << " doxyfilter -g Generate Doxyfile" << endl; output << " doxyfilter Filter the given file's code" << endl; } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); if (argc == 1) return QProcess::execute("doxygen"); else if (argc < 2) { usage(); return 1; } if (!strcmp(argv[1], "-g")) { // generate default Doxyfile QProcess process; process.start("doxygen", QStringList() << "-g" << "-"); if (!process.waitForFinished()) { qWarning("Could not run doxygen"); return 1; } QString code = QString::fromUtf8(process.readAll()); QString docDir = (argc > 2) ? (QString::fromLocal8Bit(argv[2]) + "/") : ""; QStringList docFiles = QStringList() << "index.doc" << "using.doc" << "xep.doc" << "../src"; for (int i = 0; i < docFiles.size(); ++i) { docFiles[i] = docDir + docFiles[i]; } // adjust Doxyfile setField(code, "ALPHABETICAL_INDEX", "NO"); setField(code, "EXCLUDE_PATTERNS", "*/moc_* */mod_* */qdnslookup* */*_p.h */QXmppCodec.cpp */QXmppSasl.cpp"); setField(code, "FULL_PATH_NAMES", "NO"); setField(code, "HIDE_UNDOC_CLASSES", "YES"); setField(code, "GENERATE_LATEX", "NO"); setField(code, "HTML_TIMESTAMP", "NO"); setField(code, "INPUT", docFiles.join(" ")); setField(code, "INPUT_FILTER", QString::fromLocal8Bit(argv[0])); setField(code, "PROJECT_NAME", "QXmpp"); setField(code, "PROJECT_NUMBER", QString("Version: %1.%2.%3").arg( QString::number((QXMPP_VERSION >> 16) & 0xff), QString::number((QXMPP_VERSION >> 8) & 0xff), QString::number(QXMPP_VERSION & 0xff))); setField(code, "QUIET", "YES"); setField(code, "RECURSIVE", "YES"); // write doxyfile QFile output("Doxyfile"); if (!output.open(QIODevice::WriteOnly)) { qWarning("Could not write to %s", qPrintable(output.fileName())); return 1; } output.write(code.toUtf8()); output.close(); } else if (!strcmp(argv[1], "-h")) { usage(); return 0; } else { // read source code QFile source(QString::fromLocal8Bit(argv[1])); if (!source.open(QIODevice::ReadOnly)) { qWarning("Could not open %s", qPrintable(source.fileName())); return 1; } QString code = QString::fromUtf8(source.readAll()); source.close(); // add links for RFCs QRegExp rfcRegexp("(RFC ([0-9]{4})(: [^\\s.]+( [A-Z][^\\s.]*)*)?)"); code.replace(rfcRegexp, "\\1"); // add links for XEPs QRegExp regexp("(XEP-([0-9]{4})(: [^\\s.]+( [A-Z][^\\s.]*)*)?)"); code.replace(regexp, "\\1"); QTextStream output(stdout); output << code; } return 0; } qxmpp-0.9.3/doc/index.doc000066400000000000000000000021071263006255200152340ustar00rootroot00000000000000/*! \mainpage QXmpp is a cross-platform C++ XMPP client library based on the Qt framework. It tries to use Qt's programming conventions in order to ease the learning curve for new programmers. QXmpp based clients are built using QXmppClient instances which handle the establishment of the XMPP connection and provide a number of high-level "managers" to perform specific tasks. You can write your own managers to extend QXmpp by subclassing QXmppClientExtension. Main Class: - QXmppClient Managers to perform specific tasks: - QXmppRosterManager - QXmppVCardManager - QXmppTransferManager - QXmppMucManager - QXmppCallManager - QXmppArchiveManager - QXmppVersionManager - QXmppDiscoveryManager - QXmppEntityTimeManager XMPP stanzas: If you are interested in a more low-level API, you can refer to these classes. - QXmppIq - QXmppMessage - QXmppPresence Project Details: - Project Page: https://github.com/qxmpp-project/qxmpp/ - Report Issues: https://github.com/qxmpp-project/qxmpp/issues/ - New Releases: https://github.com/qxmpp-project/qxmpp/downloads/ */ qxmpp-0.9.3/doc/using.doc000066400000000000000000000056301263006255200152560ustar00rootroot00000000000000/*! \page using Using QXmpp

Example: example_0_connected

This example just connects to the xmpp server. And starts receiving presences (updates) from the server. After running this example, you can see this user online, if it's added in your roster (friends list). Logging type has been set to stdout. You can see the progress on the command line. This example is also available with the source code in the example directory. \code #include #include "QXmppClient.h" #include "QXmppLogger.h" int main(int argc, char *argv[]) { // create a Qt application QCoreApplication a(argc, argv); // setting the logging type to stdout QXmppLogger::getLogger()->setLoggingType(QXmppLogger::StdoutLogging); // creating the object of the client class QXmppClient // and then calling the connectToServer function to connect to gtalk server QXmppClient client; client.connectToServer("qxmpp.test1@gmail.com", "qxmpp123"); // run the application main loop return a.exec(); } \endcode

Example: example_1_echoClient

This is a very simple bot which echoes the message sent to it. Run this example, send it a message from a friend of this bot. You will receive the message back. This example shows how to receive and send messages. This example is also available with the source code in the example directory. \code // subclass the QXmppClient and create a new class echoClient // in the contructor the signal QXmppClient::messageReceived(const QXmppMessage&) // is connected to the slot echoClient::messageReceived(const QXmppMessage&) // in the slot one can process the message received #include "QXmppClient.h" class echoClient : public QXmppClient { Q_OBJECT public: echoClient(QObject *parent = 0); ~echoClient(); public slots: void messageReceived(const QXmppMessage&); }; }}} \endcode \code #include "echoClient.h" #include "QXmppMessage.h" echoClient::echoClient(QObject *parent) : QXmppClient(parent) { bool check = connect(this, SIGNAL(messageReceived(const QXmppMessage&)), SLOT(messageReceived(const QXmppMessage&))); Q_ASSERT(check); } echoClient::~echoClient() { } // slot where message sent to this client is received // here getFrom() gives the sender and getBody() gives the message // using the function sendPacket message is sent back to the sender void echoClient::messageReceived(const QXmppMessage& message) { QString from = message.getFrom(); QString msg = message.getBody(); sendPacket(QXmppMessage("", from, "Your message: " + msg)); } }}} \endcode \code #include #include "echoClient.h" #include "QXmppLogger.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QXmppLogger::getLogger()->setLoggingType(QXmppLogger::StdoutLogging); echoClient client; client.connectToServer("qxmpp.test1@gmail.com", "qxmpp123"); return a.exec(); } \endcode */ qxmpp-0.9.3/doc/xep.doc000066400000000000000000000021611263006255200147210ustar00rootroot00000000000000/*! \page xep XMPP Extensions This document lists the XMPP Extensions (XEP) available in QXmpp. Complete: - XEP-0004: Data Forms - XEP-0030: Service Discovery - XEP-0033: Extended Stanza Addressing - XEP-0045: Multi-User Chat - XEP-0047: In-Band Bytestreams - XEP-0048: Bookmarks - XEP-0054: vcard-temp - XEP-0059: Result Set Management - XEP-0065: SOCKS5 Bytestreams - XEP-0071: XHTML-IM - XEP-0078: Non-SASL Authentication - XEP-0082: XMPP Date and Time Profiles - XEP-0085: Chat State Notifications - XEP-0091: Legacy Delayed Delivery - XEP-0092: Software Version - XEP-0095: Stream Initiation - XEP-0096: SI File Transfer - XEP-0115: Entity Capabilities - XEP-0128: Service Discovery Extensions - XEP-0136: Message Archiving - XEP-0153: vCard-Based Avatars - XEP-0166: Jingle - XEP-0167: Jingle RTP Sessions - XEP-0176: Jingle ICE-UDP Transport Method - XEP-0184: Message Delivery Receipts - XEP-0199: XMPP Ping - XEP-0202: Entity Time - XEP-0203: Delayed Delivery - XEP-0221: Data Forms Media Element - XEP-0224: Attention Ongoing: - XEP-0009: Jabber-RPC TODO: - XEP-0060: Publish-Subscribe - XEP-0077: In-Band Registration */ qxmpp-0.9.3/examples/000077500000000000000000000000001263006255200145075ustar00rootroot00000000000000qxmpp-0.9.3/examples/GuiClient/000077500000000000000000000000001263006255200163725ustar00rootroot00000000000000qxmpp-0.9.3/examples/GuiClient/GuiClient.pro000066400000000000000000000025301263006255200207770ustar00rootroot00000000000000include(../examples.pri) TARGET = GuiClient TEMPLATE = app SOURCES += main.cpp \ chatMsgGraphicsItem.cpp \ chatGraphicsScene.cpp \ chatGraphicsView.cpp \ chatDialog.cpp \ mainDialog.cpp \ rosterItemModel.cpp \ rosterItem.cpp \ rosterItemSortFilterProxyModel.cpp \ utils.cpp \ rosterListView.cpp \ searchLineEdit.cpp \ statusWidget.cpp \ signInStatusLabel.cpp \ statusAvatarWidget.cpp \ statusTextWidget.cpp \ statusToolButton.cpp \ vCardCache.cpp \ profileDialog.cpp \ capabilitiesCache.cpp \ accountsCache.cpp \ xmlConsoleDialog.cpp \ aboutDialog.cpp HEADERS += chatMsgGraphicsItem.h \ chatGraphicsScene.h \ chatGraphicsView.h \ chatDialog.h \ mainDialog.h \ rosterItemModel.h \ rosterItem.h \ rosterItemSortFilterProxyModel.h \ utils.h \ rosterListView.h \ searchLineEdit.h \ statusWidget.h \ signInStatusLabel.h \ statusAvatarWidget.h \ statusTextWidget.h \ statusToolButton.h \ vCardCache.h \ profileDialog.h \ capabilitiesCache.h \ accountsCache.h \ xmlConsoleDialog.h \ aboutDialog.h FORMS += mainDialog.ui \ chatDialog.ui \ statusWidget.ui \ profileDialog.ui \ xmlConsoleDialog.ui \ aboutDialog.ui QT += network \ xml \ widgets RESOURCES += resources.qrc qxmpp-0.9.3/examples/GuiClient/aboutDialog.cpp000066400000000000000000000027251263006255200213360ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "aboutDialog.h" #include "ui_aboutDialog.h" #include "QXmppGlobal.h" #include aboutDialog::aboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::aboutDialog) { ui->setupUi(this); setWindowTitle(QString("About %1").arg(qApp->applicationName())); ui->textEdit->append(QString("Copyright (C) 2008-2014 The QXmpp developers\n")); ui->textEdit->append(qApp->applicationName() + " " + qApp->applicationVersion()); ui->textEdit->append(QString("\nBased on:")); ui->textEdit->append(QString("QXmpp %1").arg(QXmppVersion())); ui->textEdit->append(QString("Qt %1 [built-with]").arg(qVersion())); ui->textEdit->append(QString("Qt %1 [running-with]").arg(QT_VERSION_STR)); } aboutDialog::~aboutDialog() { delete ui; } qxmpp-0.9.3/examples/GuiClient/aboutDialog.h000066400000000000000000000017571263006255200210070ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 ABOUTDIALOG_H #define ABOUTDIALOG_H #include namespace Ui { class aboutDialog; } class aboutDialog : public QDialog { Q_OBJECT public: explicit aboutDialog(QWidget *parent = 0); ~aboutDialog(); private: Ui::aboutDialog *ui; }; #endif // ABOUTDIALOG_H qxmpp-0.9.3/examples/GuiClient/aboutDialog.ui000066400000000000000000000030511263006255200211620ustar00rootroot00000000000000 aboutDialog 0 0 309 218 Dialog true Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() aboutDialog accept() 248 254 157 274 buttonBox rejected() aboutDialog reject() 316 260 286 274 qxmpp-0.9.3/examples/GuiClient/accountsCache.cpp000066400000000000000000000072511263006255200216460ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "accountsCache.h" #include "utils.h" #include #include #include accountsCache::accountsCache(QObject *parent) : QObject(parent) { } QStringList accountsCache::getBareJids() { QStringList list; QDomElement element = m_accountsDocument.documentElement().firstChildElement("account"); while(!element.isNull()) { list << element.firstChildElement("bareJid").text(); element = element.nextSiblingElement("account"); } return list; } QString accountsCache::getPassword(const QString& bareJid) { QDomElement element = m_accountsDocument.documentElement().firstChildElement("account"); while(!element.isNull()) { if(element.firstChildElement("bareJid").text() == bareJid) { QByteArray passwdEncryptedBa = QByteArray::fromBase64( element.firstChildElement("password").text().toUtf8()); QString passwd = calculateXor(passwdEncryptedBa, bareJid.toUtf8()); return passwd; } element = element.nextSiblingElement("account"); } return ""; } void accountsCache::addAccount(const QString& bareJid, const QString& passwd) { if(m_accountsDocument.documentElement().isNull()) { m_accountsDocument.appendChild(m_accountsDocument.createElement("accounts")); } QDomElement element = m_accountsDocument.documentElement().firstChildElement("account"); while(!element.isNull()) { if(element.firstChildElement("bareJid").text() == bareJid) { m_accountsDocument.documentElement().removeChild(element); break; } element = element.nextSiblingElement("account"); } QDomElement newElement = m_accountsDocument.createElement("account"); QDomElement newElementBareJid = m_accountsDocument.createElement("bareJid"); newElementBareJid.appendChild(m_accountsDocument.createTextNode(bareJid)); newElement.appendChild(newElementBareJid); QDomElement newElementPasswd = m_accountsDocument.createElement("password"); newElementPasswd.appendChild(m_accountsDocument.createTextNode( calculateXor(passwd.toUtf8(), bareJid.toUtf8()).toBase64())); newElement.appendChild(newElementPasswd); m_accountsDocument.documentElement().appendChild(newElement); saveToFile(); } void accountsCache::loadFromFile() { QDir dirSettings(getSettingsDir()); if(dirSettings.exists()) { QFile file(getSettingsDir()+ "accounts.xml"); if(file.open(QIODevice::ReadOnly)) { m_accountsDocument.setContent(&file, true); } } } void accountsCache::saveToFile() { QDir dir; if(!dir.exists(getSettingsDir())) dir.mkpath(getSettingsDir()); QString fileAccounts = getSettingsDir() + "accounts.xml"; QFile file(fileAccounts); if(file.open(QIODevice::ReadWrite)) { QTextStream tstream(&file); m_accountsDocument.save(tstream, 2); file.close(); } } qxmpp-0.9.3/examples/GuiClient/accountsCache.h000066400000000000000000000022761263006255200213150ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 ACCOUNTSCACHE_H #define ACCOUNTSCACHE_H #include #include class QStringList; class accountsCache : public QObject { Q_OBJECT public: explicit accountsCache(QObject *parent); QStringList getBareJids(); QString getPassword(const QString& bareJid); void addAccount(const QString& bareJid, const QString& passwd); public: void loadFromFile(); private: void saveToFile(); QDomDocument m_accountsDocument; }; #endif // ACCOUNTSCACHE_H qxmpp-0.9.3/examples/GuiClient/capabilitiesCache.cpp000066400000000000000000000123771263006255200224650ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "capabilitiesCache.h" #include "utils.h" #include "QXmppClient.h" #include "QXmppDiscoveryManager.h" #include #include #include capabilitiesCache::capabilitiesCache(QXmppClient* client) : QObject(client), m_client(client) { QXmppDiscoveryManager* ext = m_client->findExtension(); if(ext) { bool check = connect(ext, SIGNAL(infoReceived(QXmppDiscoveryIq)), SLOT(infoReceived(QXmppDiscoveryIq))); Q_ASSERT(check); Q_UNUSED(check); } } bool capabilitiesCache::isCapabilityAvailable(const QString& nodeVer) { return m_mapCapabilities.contains(nodeVer); } void capabilitiesCache::requestInfo(const QString& jid, const QString& node) { QXmppDiscoveryManager* ext = m_client->findExtension(); if(ext) { bool alreadyRequested = false; foreach(QString key, m_mapIdNodeVer.keys()) { if(m_mapIdNodeVer[key] == node) { alreadyRequested = true; break; } } if(!alreadyRequested) { QString id = ext->requestInfo(jid, node); m_mapIdNodeVer[id] = node; } } } void capabilitiesCache::infoReceived(const QXmppDiscoveryIq& discoIqRcv) { QXmppDiscoveryIq discoIq = discoIqRcv; if(discoIq.queryType() == QXmppDiscoveryIq::InfoQuery && discoIq.type() == QXmppIq::Result) { if(discoIq.queryNode().isEmpty()) { discoIq.setQueryNode(m_mapIdNodeVer[discoIq.id()]); m_mapIdNodeVer.remove(discoIq.id()); } discoIq.setTo(""); discoIq.setFrom(""); discoIq.setId(""); m_mapCapabilities[discoIq.queryNode()] = discoIq; saveToFile(discoIq.queryNode()); } } void capabilitiesCache::loadFromFile() { m_mapCapabilities.clear(); QDir dirCaps(getSettingsDir(m_client->configuration().jidBare())+ "capabilities/"); if(dirCaps.exists()) { QStringList list = dirCaps.entryList(QStringList("*.xml")); foreach(QString fileName, list) { QFile file(getSettingsDir(m_client->configuration().jidBare())+ "capabilities/" + fileName); if(file.open(QIODevice::ReadOnly)) { QDomDocument doc; if(doc.setContent(&file, true)) { QXmppDiscoveryIq discoIq; discoIq.parse(doc.documentElement()); m_mapCapabilities[discoIq.queryNode()] = discoIq; QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } } } } } void capabilitiesCache::saveToFile(const QString& nodeVer) { if(!m_mapCapabilities.contains(nodeVer)) return; QString fileName = getSha1HashAsHex(nodeVer.toUtf8()); QDir dir; if(!dir.exists(getSettingsDir(m_client->configuration().jidBare()))) dir.mkpath(getSettingsDir(m_client->configuration().jidBare())); QDir dir2; if(!dir2.exists(getSettingsDir(m_client->configuration().jidBare())+ "capabilities/")) dir2.mkpath(getSettingsDir(m_client->configuration().jidBare())+ "capabilities/"); QString fileCapability = getSettingsDir(m_client->configuration().jidBare()) + "capabilities/" + fileName + ".xml"; QFile file(fileCapability); if(file.open(QIODevice::ReadWrite)) { QXmlStreamWriter stream(&file); stream.setAutoFormatting(true); stream.setAutoFormattingIndent(2); m_mapCapabilities[nodeVer].toXml(&stream); file.close(); } } QStringList capabilitiesCache::getFeatures(const QString& nodeVer) { if(!m_mapCapabilities.contains(nodeVer)) return QStringList(); return m_mapCapabilities[nodeVer].features(); } QStringList capabilitiesCache::getIdentities(const QString& nodeVer) { if(!m_mapCapabilities.contains(nodeVer)) return QStringList(); QStringList idList; QList list = m_mapCapabilities[nodeVer].identities(); foreach(QXmppDiscoveryIq::Identity identity, list) { QStringList tmpList; if(!identity.name().isEmpty()) tmpList << identity.name(); if(!identity.category().isEmpty()) tmpList << identity.category(); if(!identity.type().isEmpty()) tmpList << identity.type(); if(!identity.language().isEmpty()) tmpList << identity.language(); idList << tmpList.join(" | "); } return idList; } qxmpp-0.9.3/examples/GuiClient/capabilitiesCache.h000066400000000000000000000027771263006255200221350ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 CAPABILITIESCACHE_H #define CAPABILITIESCACHE_H #include #include #include class QXmppClient; #include "QXmppDiscoveryIq.h" class capabilitiesCache : public QObject { Q_OBJECT public: capabilitiesCache(QXmppClient* client); bool isCapabilityAvailable(const QString& nodeVer); void requestInfo(const QString& jid, const QString& nodeVer); void loadFromFile(); QStringList getFeatures(const QString& nodeVer); QStringList getIdentities(const QString& nodeVer); signals: private slots: void infoReceived(const QXmppDiscoveryIq&); private: void saveToFile(const QString& nodeVer); QXmppClient* m_client; QMap m_mapCapabilities; QMap m_mapIdNodeVer; }; #endif // CAPABILITIESCACHE_H qxmpp-0.9.3/examples/GuiClient/chatDialog.cpp000066400000000000000000000073001263006255200211350ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "chatDialog.h" #include "ui_chatDialog.h" #include "chatGraphicsView.h" #include "chatGraphicsScene.h" #include "QXmppClient.h" #include #include chatDialog::chatDialog(QWidget *parent): QDialog(parent, Qt::Window), ui(new Ui::chatDialogClass), m_view(0), m_scene(0), m_pushButtonSend(0), m_client(0) { ui->setupUi(this); m_view = new chatGraphicsView(this); m_scene = new chatGraphicsScene(this); m_view->setChatGraphicsScene(m_scene); m_pushButtonSend = new QPushButton("Send", this); // m_pushButtonSend->setFixedHeight(); // m_pushButtonSend->setFixedWidth(); QRect rect = ui->lineEdit->geometry(); rect.setLeft(rect.right()); rect.setWidth(60); m_pushButtonSend->setGeometry(rect); ui->lineEdit->setFocus(); ui->verticalLayout->insertWidget(0, m_view); bool check = connect(m_pushButtonSend, SIGNAL(clicked(bool)), SLOT(sendMessage())); Q_ASSERT(check); Q_UNUSED(check); updateSendButtonGeomerty(); } void chatDialog::show() { QDialog::show(); } QString chatDialog::getBareJid() const { return m_bareJid; } QString chatDialog::getDisplayName() const { return m_displayName; } void chatDialog::setBareJid(const QString& str) { m_bareJid = str; } void chatDialog::setDisplayName(const QString& str) { m_displayName = str; setWindowTitle(QString("Chat with %1").arg(m_bareJid)); QFont font; font.setBold(true); QFontMetrics fontMetrics(font); QRect rect = fontMetrics.boundingRect(m_displayName); int width = rect.width(); if(m_scene) m_scene->setBoxStartLength(width); // ui->horizontalSpacer_2->changeSize(width+20, 10); ui->lineEdit->setFixedWidth(350 - width - 25); updateSendButtonGeomerty(); } void chatDialog::setQXmppClient(QXmppClient* client) { m_client = client; } void chatDialog::sendMessage() { if(m_client) m_client->sendMessage(getBareJid(), ui->lineEdit->text()); m_view->addMessage("Me", ui->lineEdit->text()); ui->lineEdit->clear(); } void chatDialog::messageReceived(const QString& msg) { m_view->addMessage(getDisplayName(), msg); } void chatDialog::keyPressEvent(QKeyEvent* event1) { ui->lineEdit->setFocus(); ui->lineEdit->event(event1); if(event1->key() == Qt::Key_Return) { m_pushButtonSend->click(); } else if(event1->key() == Qt::Key_Escape) { hide(); } } void chatDialog::paintEvent(QPaintEvent* event) { QDialog::paintEvent(event); QPainter p(this); p.setPen(Qt::gray); p.drawRect(rect().adjusted(5, 5, -6, -6)); } void chatDialog::resizeEvent(QResizeEvent *) { updateSendButtonGeomerty(); } void chatDialog::moveEvent(QMoveEvent *) { updateSendButtonGeomerty(); } void chatDialog::updateSendButtonGeomerty() { QRect rect = ui->lineEdit->geometry(); rect.setLeft(rect.right() + 6); rect.setWidth(60); QRect rect2 = rect; rect2.setHeight(25); rect2.moveCenter(rect.center()); m_pushButtonSend->setGeometry(rect2); } qxmpp-0.9.3/examples/GuiClient/chatDialog.h000066400000000000000000000034441263006255200206070ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 CHATDIALOG_H #define CHATDIALOG_H #include #include namespace Ui { class chatDialogClass; } class chatGraphicsView; class chatGraphicsScene; class QXmppClient; class QPushButton; class chatDialog : public QDialog { Q_OBJECT public: chatDialog(QWidget *parent = 0); void show(); QString getBareJid() const; QString getDisplayName() const; void setBareJid(const QString&); void setDisplayName(const QString&); void setQXmppClient(QXmppClient* client); void messageReceived(const QString& msg); private slots: void sendMessage(); protected: void keyPressEvent(QKeyEvent*); void paintEvent(QPaintEvent* event); virtual void resizeEvent(QResizeEvent*); virtual void moveEvent(QMoveEvent*); private: void updateSendButtonGeomerty(); Ui::chatDialogClass *ui; chatGraphicsView* m_view; chatGraphicsScene* m_scene; QPushButton* m_pushButtonSend; // holds a reference to the the connected client QXmppClient* m_client; QString m_bareJid; QString m_displayName; }; #endif // CHATDIALOG_H qxmpp-0.9.3/examples/GuiClient/chatDialog.ui000066400000000000000000000042311263006255200207700ustar00rootroot00000000000000 chatDialogClass 0 0 445 291 445 0 Dialog alternate-background-color: rgb(255, 255, 255); 0 6 0 0 0 background-color: rgb(255, 255, 255); 0 50 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 0 0 background-color: rgb(255, 255, 255); qxmpp-0.9.3/examples/GuiClient/chatGraphicsScene.cpp000066400000000000000000000047471263006255200224700ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "chatGraphicsScene.h" #include "chatMsgGraphicsItem.h" #include "chatGraphicsView.h" chatGraphicsScene::chatGraphicsScene(QObject* parent) : QGraphicsScene(parent), m_verticalPosForNewMessage(0), m_verticalSpacing(5) { } void chatGraphicsScene::addMessage(const QString& user, const QString& message) { chatMsgGraphicsItem* item = new chatMsgGraphicsItem(); m_items.append(item); item->setName(user); item->setBoxStartLength(m_boxStartLength); item->setText(message); item->setViewWidth(350); // item->setViewWidth(views().at(0)->size().width()); item->setPos(0, m_verticalPosForNewMessage); int height = item->boundingRect().height(); m_verticalPosForNewMessage = m_verticalPosForNewMessage + height + m_verticalSpacing; addItem(item); QRectF rect = sceneRect(); rect.setHeight(m_verticalPosForNewMessage); setSceneRect(rect); } void chatGraphicsScene::setWidthResize(int newWidth, int oldWidth) { Q_UNUSED(newWidth); Q_UNUSED(oldWidth); // verticalReposition(); } void chatGraphicsScene::verticalReposition() { m_verticalPosForNewMessage = 0; chatMsgGraphicsItem* item = 0; for(int i = 0; i < m_items.size(); ++i) { item = m_items.at(i); item->setViewWidth(views().at(0)->size().width()); item->setPos(0, m_verticalPosForNewMessage); int height = item->boundingRect().height(); m_verticalPosForNewMessage = m_verticalPosForNewMessage + height + m_verticalSpacing; } QRectF rect = sceneRect(); if(item) { rect.setHeight(m_verticalPosForNewMessage); rect.setWidth(item->getMaxWidth() + item->getBoxStartLength() - 4); setSceneRect(rect); } } void chatGraphicsScene::setBoxStartLength(int length) { m_boxStartLength = length; } qxmpp-0.9.3/examples/GuiClient/chatGraphicsScene.h000066400000000000000000000024341263006255200221240ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 CHATGRAPHICSSCENE_H #define CHATGRAPHICSSCENE_H #include #include class chatMsgGraphicsItem; class chatGraphicsScene : public QGraphicsScene { public: chatGraphicsScene(QObject* parent = 0); void addMessage(const QString& user, const QString& message); void setWidthResize(int newWidth, int oldWidth); void verticalReposition(); void setBoxStartLength(int length); private: int m_verticalPosForNewMessage; int m_verticalSpacing; int m_boxStartLength; QList m_items; }; #endif // CHATGRAPHICSSCENE_H qxmpp-0.9.3/examples/GuiClient/chatGraphicsView.cpp000066400000000000000000000035011263006255200223300ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "chatGraphicsView.h" #include "chatGraphicsScene.h" #include chatGraphicsView::chatGraphicsView(QWidget* parent) : QGraphicsView(parent) { setAlignment(Qt::AlignHCenter|Qt::AlignTop); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setFrameStyle(QFrame::NoFrame); } void chatGraphicsView::setChatGraphicsScene(chatGraphicsScene* scene) { m_scene = scene; setScene(m_scene); } void chatGraphicsView::addMessage(const QString& user, const QString& message) { if(m_scene) m_scene->addMessage(user, message); QRectF rect = scene()->sceneRect(); rect.adjust(-4, -4, 4, 4); setSceneRect(rect); rect = sceneRect(); rect.setTop(sceneRect().height() - 20); rect.setWidth(20); ensureVisible(rect, 50, 50); } void chatGraphicsView::resizeEvent(QResizeEvent *event) { // pass this to scene m_scene->setWidthResize(event->size().width(), event->oldSize().width()); QGraphicsView::resizeEvent(event); QRectF rect = scene()->sceneRect(); rect.adjust(-4, -4, 4, 4); setSceneRect(rect); } qxmpp-0.9.3/examples/GuiClient/chatGraphicsView.h000066400000000000000000000022071263006255200217770ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 CHATGRAPHICSVIEW_H #define CHATGRAPHICSVIEW_H #include class chatGraphicsScene; class chatGraphicsView : public QGraphicsView { public: chatGraphicsView(QWidget* parent = 0); void setChatGraphicsScene(chatGraphicsScene* scene); void addMessage(const QString& user, const QString& message); private: void resizeEvent(QResizeEvent *event); chatGraphicsScene* m_scene; }; #endif // CHATGRAPHICSVIEW_H qxmpp-0.9.3/examples/GuiClient/chatMsgGraphicsItem.cpp000066400000000000000000000200271263006255200227650ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "chatMsgGraphicsItem.h" #include #include #include QLinearGradient getGradient(const QColor &col, const QRectF &rect) { QLinearGradient g(rect.topLeft(), rect.bottomLeft()); qreal hue = col.hueF(); qreal value = col.valueF(); qreal saturation = col.saturationF(); QColor c = col; c.setHsvF(hue, 0.42 * saturation, 0.98 * value); g.setColorAt(0, c); c.setHsvF(hue, 0.58 * saturation, 0.95 * value); g.setColorAt(0.25, c); c.setHsvF(hue, 0.70 * saturation, 0.93 * value); g.setColorAt(0.5, c); c.setHsvF(hue, 0.95 * saturation, 0.9 * value); g.setColorAt(0.501, c); c.setHsvF(hue * 0.95, 0.95 * saturation, 0.95 * value); g.setColorAt(0.75, c); c.setHsvF(hue * 0.90, 0.95 * saturation, 1 * value); g.setColorAt(1.0, c); return g; } QLinearGradient darken(const QLinearGradient &gradient) { QGradientStops stops = gradient.stops(); for (int i = 0; i < stops.size(); ++i) { QColor color = stops.at(i).second; stops[i].second = color.darker(160); } QLinearGradient g = gradient; g.setStops(stops); return g; } static void drawPath(QPainter *p, const QPainterPath &path, const QColor &col, bool dark = false) { const QRectF pathRect = path.boundingRect(); const QLinearGradient baseGradient = getGradient(col, pathRect); const QLinearGradient darkGradient = darken(baseGradient); p->save(); // p->setOpacity(0.25); //glow // if (dark) // p->strokePath(path, QPen(darkGradient, 6)); // else // p->strokePath(path, QPen(baseGradient, 6)); p->setOpacity(1.0); //fill if (dark) p->fillPath(path, darkGradient); else p->fillPath(path, baseGradient); QLinearGradient g(pathRect.topLeft(), pathRect.topRight()); g.setCoordinateMode(QGradient::ObjectBoundingMode); p->setOpacity(0.2); p->fillPath(path, g); p->setOpacity(0.5); // highlight // if (dark) // p->strokePath(path, QPen(col.lighter(160).darker(160), 2)); // else // p->strokePath(path, QPen(col.lighter(160), 2)); p->setOpacity(1.0); p->restore(); } chatMsgGraphicsItem::chatMsgGraphicsItem(QGraphicsItem * parent):QGraphicsPathItem(parent), m_spikeWidth(9), m_spikeHeight(6), m_cornerRadius(10), m_textSpacing(4), m_color(Qt::yellow) { setPath(createPath()); // setFlags(QGraphicsItem::ItemIsMovable); QFont font; QFontMetrics fm(font); m_timeStampWidth = fm.width(getTime()) + 4; } void chatMsgGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); Q_UNUSED(widget); painter->setRenderHint(QPainter::Antialiasing); drawPath(painter, path(), m_color); // int spike_x = m_spikeWidth; // int spike_y = m_spikeHeight; // int corner = m_cornerRadius; // int length = m_width - spike_x; // int offset = spike_x; QFont font; font.setBold(true); QTextDocument textDoc(getText()); QTextOption textOp; textOp.setWrapMode(QTextOption::WrapAnywhere); textOp.setAlignment(Qt::AlignLeft); textDoc.setDefaultTextOption(textOp); textDoc.setTextWidth(getTextWidth()); textDoc.setDefaultFont(font); painter->setPen(Qt::white); painter->setFont(font); int height = (int) textDoc.size().height(); painter->drawText(m_spikeWidth + m_cornerRadius, 4, getTextWidth(), height, Qt::AlignLeft|Qt::TextWrapAnywhere, getText()); // painter->setPen(Qt::gray); painter->setPen(Qt::black); // font.setBold(false); painter->setFont(font); painter->drawText(-m_boxStartLength, 0, m_boxStartLength, m_height, Qt::AlignRight|Qt::AlignBottom, getName()); font.setBold(false); painter->setPen(Qt::gray); painter->setFont(font); int timeWidth; if(m_timeStampWidth > m_boxStartLength) timeWidth = m_timeStampWidth; else timeWidth = m_boxStartLength; painter->drawText(getMaxWidth() + 6, 0, timeWidth - 6, m_height, Qt::AlignBottom|Qt::AlignLeft, getTime()); } void chatMsgGraphicsItem::setText(const QString& text) { m_text = text; calculateWidth(); setPath(createPath()); } void chatMsgGraphicsItem::setMaxWidth(int width) { m_maxWidth = width; setPath(createPath()); } void chatMsgGraphicsItem::setViewWidth(int width) { //25 for scrollbar setMaxWidth(width - getBoxStartLength() - 25); } int chatMsgGraphicsItem::getMaxWidth() const { return m_maxWidth; } void chatMsgGraphicsItem::setAlignment(Alignment align) { m_alignment = align; setPath(createPath()); } QPainterPath chatMsgGraphicsItem::createPath() { calculateWidth(); int spike_x = m_spikeWidth; int spike_y = m_spikeHeight; int corner = m_cornerRadius; int length = m_width - spike_x; int offset = spike_x; QPainterPath messageBoxPath; messageBoxPath.moveTo(0 + offset, m_height - corner); QRectF rect(offset - 2*spike_x, m_height - corner - spike_y, 2*spike_x, 2*spike_y); messageBoxPath.arcMoveTo(rect, -90.0); messageBoxPath.arcTo(rect, 270, 90.0); messageBoxPath.lineTo(0 + offset, corner); messageBoxPath.arcTo(0 + offset, 0, 2*corner, 2*corner, 180, -90.0); messageBoxPath.lineTo(length - corner, 0); messageBoxPath.arcTo(length + offset - corner*2, 0, 2*corner, 2*corner, 90, -90.0); messageBoxPath.lineTo(length + offset, m_height - corner); messageBoxPath.arcTo(length + offset - corner*2, m_height - 2*corner, 2*corner, 2*corner, 0, -90.0); messageBoxPath.lineTo(offset + corner, m_height); messageBoxPath.arcTo(offset, m_height - 2*corner, 2*corner, 2*corner, 270, -45.0); messageBoxPath.closeSubpath(); return messageBoxPath; } QString chatMsgGraphicsItem::getText() const { return m_text; } int chatMsgGraphicsItem::getTextWidth() const { return getMaxWidth() - m_spikeWidth - m_cornerRadius*2; } void chatMsgGraphicsItem::calculateWidth() { QFont font; font.setBold(true); QTextDocument textDoc(m_text); textDoc.setDefaultFont(font); int idealWidth = (int)textDoc.size().width(); textDoc.setTextWidth(getTextWidth()); m_height = (int)textDoc.size().height(); if(idealWidth < getTextWidth()) { m_width = idealWidth + m_spikeWidth + m_cornerRadius; } else m_width = getMaxWidth(); } void chatMsgGraphicsItem::setName(const QString& name) { m_name = name; if(name != "Me") m_color = QColor(0, 210, 250); else m_color = QColor(250, 188, 239); } QString chatMsgGraphicsItem::getName() const { return m_name; } QString chatMsgGraphicsItem::getTime() const { return QTime::currentTime().toString("hh:mm"); } void chatMsgGraphicsItem::setBoxStartLength(int length) { m_boxStartLength = length; } int chatMsgGraphicsItem::getBoxStartLength() const { return m_boxStartLength; } void chatMsgGraphicsItem::setColor(const QColor& color) { m_color = color; } QRectF chatMsgGraphicsItem::boundingRect() const { QRectF rect = QGraphicsPathItem::boundingRect(); rect.setLeft(-getBoxStartLength()); int timeWidth; if(m_timeStampWidth > m_boxStartLength) timeWidth = m_timeStampWidth; else timeWidth = m_boxStartLength; rect.setRight(getMaxWidth() + timeWidth); return rect; } qxmpp-0.9.3/examples/GuiClient/chatMsgGraphicsItem.h000066400000000000000000000040251263006255200224320ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 CHATMSGGRAPHICSITEM_H #define CHATMSGGRAPHICSITEM_H #include class chatMsgGraphicsItem : public QGraphicsPathItem { public: enum Alignment { LEFT = 0, RIGHT }; chatMsgGraphicsItem(QGraphicsItem * parent = 0); void setText(const QString& text); void setName(const QString& name); QString getName() const; QString getText() const; void setMaxWidth(int width); int getMaxWidth() const; void setViewWidth(int viewWidth); void setAlignment(Alignment align); void setBoxStartLength(int length); int getBoxStartLength() const; void setColor(const QColor&); virtual QRectF boundingRect() const; private: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); QPainterPath createPath(); int getTextWidth() const; void calculateWidth(); QString getTime() const; // max width of bubble including the spike int m_maxWidth; // actual width int m_width; // height of bubble int m_height; int m_spikeWidth; int m_spikeHeight; int m_cornerRadius; int m_textSpacing; int m_boxStartLength; int m_timeStampWidth; QColor m_color; QString m_text; QString m_name; int m_length; Alignment m_alignment; }; #endif // CHATMSGGRAPHICSITEM_H qxmpp-0.9.3/examples/GuiClient/main.cpp000066400000000000000000000021511263006255200200210ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "mainDialog.h" #include "utils.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); QApplication::setOrganizationName("QXmpp"); QApplication::setApplicationName("GuiClient"); QDir dir; if(!dir.exists(getSettingsDir())) dir.mkpath(getSettingsDir()); mainDialog cw; cw.show(); cw.raise(); return a.exec(); } qxmpp-0.9.3/examples/GuiClient/mainDialog.cpp000066400000000000000000000650601263006255200211510ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "mainDialog.h" #include "ui_mainDialog.h" #include "utils.h" #include "profileDialog.h" #include "aboutDialog.h" #include "chatDialog.h" #include "QXmppPresence.h" #include "QXmppMessage.h" #include "QXmppUtils.h" #include "QXmppVCardManager.h" #include #include #include #include #include mainDialog::mainDialog(QWidget *parent): QDialog(parent, Qt::Window), ui(new Ui::mainDialogClass), m_rosterItemModel(this), m_rosterItemSortFilterModel(this), m_vCardCache(&m_xmppClient), m_capabilitiesCache(&m_xmppClient), m_accountsCache(this), #ifndef QT_NO_SYSTEMTRAYICON m_trayIcon(this), m_trayIconMenu(this), #endif m_quitAction("Quit", this), m_signOutAction("Sign out", this), m_settingsMenu(0) { bool check; Q_UNUSED(check); ui->setupUi(this); createTrayIconAndMenu(); createSettingsMenu(); ui->pushButton_cancel->setDisabled(true); ui->label_throbber->setMovie(new QMovie(":/icons/resource/ajax-loader.gif")); ui->label_throbber->movie()->start(); showSignInPage(); loadAccounts(); check = connect(ui->lineEdit_userName->completer(), SIGNAL(activated(QString)), this, SLOT(userNameCompleter_activated(QString))); Q_ASSERT(check); check = connect(&m_xmppClient.rosterManager(), SIGNAL(rosterReceived()), this, SLOT(rosterReceived())); Q_ASSERT(check); check = connect(&m_xmppClient.rosterManager(), SIGNAL(itemChanged(QString)), this, SLOT(rosterChanged(QString))); Q_ASSERT(check); check = connect(&m_xmppClient, SIGNAL(error(QXmppClient::Error)), this, SLOT(errorClient(QXmppClient::Error))); Q_ASSERT(check); check = connect(&m_xmppClient, SIGNAL(presenceReceived(QXmppPresence)), this, SLOT(presenceReceived(QXmppPresence))); Q_ASSERT(check); QXmppLogger::getLogger()->setLoggingType(QXmppLogger::SignalLogging); check = connect(&m_xmppClient.rosterManager(), SIGNAL(presenceChanged(QString,QString)), this, SLOT(presenceChanged(QString,QString))); Q_ASSERT(check); check = connect(ui->lineEdit_filter, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); Q_ASSERT(check); check = connect(ui->listView, SIGNAL(showChatDialog(QString)), this, SLOT(showChatDialog(QString))); Q_ASSERT(check); check = connect(ui->listView, SIGNAL(showProfile(QString)), this, SLOT(showProfile(QString))); Q_ASSERT(check); check = connect(ui->listView, SIGNAL(removeContact(QString)), this, SLOT(action_removeContact(QString))); Q_ASSERT(check); check = connect(&m_xmppClient, SIGNAL(messageReceived(QXmppMessage)), SLOT(messageReceived(QXmppMessage))); Q_ASSERT(check); check = connect(ui->pushButton_signIn, SIGNAL(clicked(bool)), SLOT(signIn())); Q_ASSERT(check); check = connect(ui->pushButton_cancel, SIGNAL(clicked(bool)), SLOT(cancelSignIn())); Q_ASSERT(check); m_rosterItemSortFilterModel.setSourceModel(&m_rosterItemModel); ui->listView->setModel(&m_rosterItemSortFilterModel); m_rosterItemSortFilterModel.sort(0); rosterItemDelegate *delegate = new rosterItemDelegate(); ui->listView->setItemDelegate(delegate); ui->listView->setFocus(); ui->verticalLayout_3->insertWidget(0, &m_statusWidget); check = connect(&m_statusWidget, SIGNAL(statusTextChanged(QString)), SLOT(statusTextChanged(QString))); Q_ASSERT(check); check = connect(&m_statusWidget, SIGNAL(presenceTypeChanged(QXmppPresence::Type)), SLOT(presenceTypeChanged(QXmppPresence::Type))); Q_ASSERT(check); check = connect(&m_statusWidget, SIGNAL(presenceStatusTypeChanged(QXmppPresence::AvailableStatusType)), SLOT(presenceStatusTypeChanged(QXmppPresence::AvailableStatusType))); Q_ASSERT(check); check = connect(&m_statusWidget, SIGNAL(avatarChanged(QImage)), SLOT(avatarChanged(QImage))); Q_ASSERT(check); check = connect(&m_xmppClient, SIGNAL(connected()), SLOT(updateStatusWidget())); Q_ASSERT(check); check = connect(&m_xmppClient, SIGNAL(connected()), SLOT(showRosterPage())); Q_ASSERT(check); check = connect(&m_xmppClient, SIGNAL(connected()), SLOT(addAccountToCache())); Q_ASSERT(check); check = connect(&m_xmppClient, SIGNAL(disconnected()), SLOT(showSignInPageAfterUserDisconnection())); Q_ASSERT(check); check = connect(&m_xmppClient.vCardManager(), SIGNAL(vCardReceived(QXmppVCardIq)), &m_vCardCache, SLOT(vCardReceived(QXmppVCardIq))); Q_ASSERT(check); check = connect(&m_vCardCache, SIGNAL(vCardReadyToUse(QString)), SLOT(updateVCard(QString))); Q_ASSERT(check); check = connect(ui->pushButton_addContact, SIGNAL(clicked()), SLOT(action_addContact())); Q_ASSERT(check); check = connect(QXmppLogger::getLogger(), SIGNAL(message(QXmppLogger::MessageType,QString)), &m_consoleDlg, SLOT(message(QXmppLogger::MessageType,QString))); Q_ASSERT(check); check = connect(ui->pushButton_settings, SIGNAL(pressed()), SLOT(action_settingsPressed())); Q_ASSERT(check); } void mainDialog::rosterChanged(const QString& bareJid) { m_rosterItemModel.updateRosterEntry(bareJid, m_xmppClient.rosterManager(). getRosterEntry(bareJid)); // if available in cache, update it else based on presence it will request if not available if(m_vCardCache.isVCardAvailable(bareJid)) updateVCard(bareJid); } void mainDialog::rosterReceived() { QStringList list = m_xmppClient.rosterManager().getRosterBareJids(); QString bareJid; foreach(bareJid, list) rosterChanged(bareJid); } void mainDialog::presenceChanged(const QString& bareJid, const QString& resource) { if(bareJid == m_xmppClient.configuration().jidBare()) return; if(!m_rosterItemModel.getRosterItemFromBareJid(bareJid)) return; QString jid = bareJid + "/" + resource; QMap presences = m_xmppClient.rosterManager(). getAllPresencesForBareJid(bareJid); m_rosterItemModel.updatePresence(bareJid, presences); QXmppPresence& pre = presences[resource]; if(pre.type() == QXmppPresence::Available) { QString node = pre.capabilityNode(); QString ver = pre.capabilityVer().toBase64(); QStringList exts = pre.capabilityExt(); QString nodeVer = node + "#" + ver; if(!m_capabilitiesCache.isCapabilityAvailable(nodeVer)) m_capabilitiesCache.requestInfo(jid, nodeVer); foreach(QString ext, exts) { nodeVer = node + "#" + ext; if(!m_capabilitiesCache.isCapabilityAvailable(nodeVer)) m_capabilitiesCache.requestInfo(jid, nodeVer); } switch(pre.vCardUpdateType()) { case QXmppPresence::VCardUpdateNone: if(!m_vCardCache.isVCardAvailable(bareJid)) m_vCardCache.requestVCard(bareJid); case QXmppPresence::VCardUpdateNotReady: break; case QXmppPresence::VCardUpdateNoPhoto: case QXmppPresence::VCardUpdateValidPhoto: if(m_vCardCache.getPhotoHash(bareJid) != pre.photoHash()) m_vCardCache.requestVCard(bareJid); break; } } // QXmppPresence::Type presenceType = presences.begin().value().getType(); // if(!m_vCardCache.isVCardAvailable(bareJid) && // presenceType == QXmppPresence::Available) // { // m_rosterItemModel.updateAvatar(bareJid, // m_vCardCache.getVCard(bareJid).image); // } } void mainDialog::filterChanged(const QString& filter) { m_rosterItemSortFilterModel.setFilterRegExp(filter); // follow statement selects the first row ui->listView->selectionModel()->select(ui->listView->model()->index(0, 0), QItemSelectionModel::ClearAndSelect); } void mainDialog::keyPressEvent(QKeyEvent* event1) { if(ui->stackedWidget->currentIndex() == 0) // roster page { if(event1->matches(QKeySequence::Find) ||( event1->key() <= Qt::Key_9 && event1->key() >= Qt::Key_1) || (event1->key() <= Qt::Key_Z && event1->key() >= Qt::Key_At) || event1->key() == Qt::Key_Backspace) { ui->lineEdit_filter->setFocus(); ui->lineEdit_filter->event(event1); } else if(event1->key() == Qt::Key_Escape) { ui->lineEdit_filter->clear(); ui->listView->setFocus(); } else if(event1->key() == Qt::Key_Up || event1->key() == Qt::Key_Down || event1->key() == Qt::Key_PageUp || event1->key() == Qt::Key_PageDown) { ui->listView->setFocus(); ui->listView->event(event1); } else if(event1->key() == Qt::Key_Return && ui->listView->hasFocus()) { ui->listView->event(event1); } } // don't close on escape if(event1->key() == Qt::Key_Escape) { event1->ignore(); return; } // FIXME: I'm not sure what this is supposed to do, but it does not compile. #if 0 else if(minimize && e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) { event1->ignore(); return; } #endif // don't close on escape if(ui->stackedWidget->currentIndex() == 1) // sign in page { QDialog::keyPressEvent(event1); return; } } chatDialog* mainDialog::getChatDialog(const QString& bareJid) { if(!m_chatDlgsList.contains(bareJid)) { m_chatDlgsList[bareJid] = new chatDialog(); m_chatDlgsList[bareJid]->setBareJid(bareJid); if(!m_rosterItemModel.getRosterItemFromBareJid(bareJid)) return 0; if(!m_rosterItemModel.getRosterItemFromBareJid(bareJid)-> getName().isEmpty()) m_chatDlgsList[bareJid]->setDisplayName(m_rosterItemModel. getRosterItemFromBareJid(bareJid)->getName()); else m_chatDlgsList[bareJid]->setDisplayName(QXmppUtils::jidToUser(bareJid)); m_chatDlgsList[bareJid]->setQXmppClient(&m_xmppClient); } return m_chatDlgsList[bareJid]; } void mainDialog::showChatDialog(const QString& bareJid) { if(!bareJid.isEmpty()) getChatDialog(bareJid)->show(); } void mainDialog::messageReceived(const QXmppMessage& msg) { if (msg.body().isEmpty()) return; chatDialog *dialog = getChatDialog(QXmppUtils::jidToBareJid(msg.from())); if (dialog) { dialog->show(); dialog->messageReceived(msg.body()); } } void mainDialog::statusTextChanged(const QString& status) { QXmppPresence presence = m_xmppClient.clientPresence(); presence.setStatusText(status); addPhotoHash(presence); m_xmppClient.setClientPresence(presence); } void mainDialog::presenceTypeChanged(QXmppPresence::Type presenceType) { if(presenceType == QXmppPresence::Unavailable) { m_xmppClient.disconnectFromServer(); } else if(presenceType == QXmppPresence::Available) { QXmppPresence newPresence = m_xmppClient.clientPresence(); newPresence.setType(presenceType); newPresence.setAvailableStatusType(QXmppPresence::Online); addPhotoHash(newPresence); m_xmppClient.setClientPresence(newPresence); } m_statusWidget.setStatusText( presenceToStatusText(m_xmppClient.clientPresence())); } void mainDialog::presenceStatusTypeChanged(QXmppPresence::AvailableStatusType statusType) { QXmppPresence presence = m_xmppClient.clientPresence(); presence.setType(QXmppPresence::Available); presence.setAvailableStatusType(statusType); addPhotoHash(presence); m_xmppClient.setClientPresence(presence); m_statusWidget.setStatusText( presenceToStatusText(m_xmppClient.clientPresence())); } void mainDialog::avatarChanged(const QImage& image) { QXmppVCardIq vcard; vcard.setType(QXmppIq::Set); QByteArray ba; QBuffer buffer(&ba); if(buffer.open(QIODevice::WriteOnly)) { if(image.save(&buffer, "PNG")) { vcard.setPhoto(ba); m_xmppClient.sendPacket(vcard); m_statusWidget.setAvatar(image); m_vCardCache.getVCard(m_xmppClient.configuration().jidBare()) = vcard; // update photo hash QXmppPresence presence = m_xmppClient.clientPresence(); addPhotoHash(presence); m_xmppClient.setClientPresence(presence); } } } void mainDialog::updateStatusWidget() { const QString bareJid = m_xmppClient.configuration().jidBare(); // initialise status widget updateVCard(bareJid); m_statusWidget.setStatusText(presenceToStatusText(m_xmppClient.clientPresence())); m_statusWidget.setPresenceAndStatusType(m_xmppClient.clientPresence().type(), m_xmppClient.clientPresence().availableStatusType()); // fetch own vCard m_vCardCache.requestVCard(bareJid); } void mainDialog::signIn() { ui->label_throbber->show(); ui->pushButton_signIn->setDisabled(true); ui->pushButton_cancel->setDisabled(false); ui->lineEdit_userName->setDisabled(true); ui->lineEdit_password->setDisabled(true); ui->checkBox_rememberPasswd->setDisabled(true); showLoginStatusWithProgress("Connecting"); QString bareJid = ui->lineEdit_userName->text(); QString passwd = ui->lineEdit_password->text(); m_xmppClient.configuration().setJid(bareJid); m_xmppClient.configuration().setPassword(passwd); m_rosterItemModel.clear(); m_vCardCache.loadFromFile(); m_capabilitiesCache.loadFromFile(); startConnection(); } void mainDialog::cancelSignIn() { if(!ui->checkBox_rememberPasswd->isChecked()) ui->lineEdit_password->setText(""); ui->label_throbber->hide(); m_xmppClient.disconnectFromServer(); showSignInPage(); showLoginStatus("Sign in cancelled"); addAccountToCache(); } void mainDialog::showSignInPage() { ui->label_throbber->hide(); ui->pushButton_signIn->setDisabled(false); ui->pushButton_cancel->setDisabled(true); ui->lineEdit_userName->setDisabled(false); ui->lineEdit_password->setDisabled(false); ui->checkBox_rememberPasswd->setDisabled(false); ui->stackedWidget->setCurrentIndex(1); } void mainDialog::showSignInPageAfterUserDisconnection() { if(!ui->checkBox_rememberPasswd->isChecked()) ui->lineEdit_password->setText(""); ui->label_throbber->hide(); showLoginStatus("Disconnected"); showSignInPage(); } void mainDialog::showRosterPage() { ui->stackedWidget->setCurrentIndex(0); } void mainDialog::startConnection() { // m_xmppClient.setClientPresence(QXmppPresence()); m_xmppClient.connectToServer(m_xmppClient.configuration()); } void mainDialog::showLoginStatus(const QString& msg) { ui->label_status->setCustomText(msg, signInStatusLabel::None); } void mainDialog::showLoginStatusWithProgress(const QString& msg) { ui->label_status->setCustomText(msg, signInStatusLabel::WithProgressEllipsis); } void mainDialog::showLoginStatusWithCounter(const QString& msg, int time) { ui->label_status->setCustomText(msg, signInStatusLabel::CountDown, time); } void mainDialog::updateVCard(const QString& bareJid) { // determine full name const QXmppVCardIq vCard = m_vCardCache.getVCard(bareJid); QString fullName = vCard.fullName(); if (fullName.isEmpty()) fullName = bareJid; // determine avatar QImage avatar = m_vCardCache.getAvatar(bareJid); if (avatar.isNull()) avatar = QImage(":/icons/resource/avatar.png"); if (bareJid == m_xmppClient.configuration().jidBare()) { // update our own information m_statusWidget.setAvatar(avatar); m_statusWidget.setDisplayName(fullName); } else { // update roster information m_rosterItemModel.updateAvatar(bareJid, avatar); m_rosterItemModel.updateName(bareJid, fullName); } } void mainDialog::showProfile(const QString& bareJid) { if(bareJid.isEmpty()) return; profileDialog dlg(this, bareJid, m_xmppClient, m_capabilitiesCache); dlg.setBareJid(bareJid); // TODO use original image if(!m_vCardCache.getAvatar(bareJid).isNull()) dlg.setAvatar(m_vCardCache.getAvatar(bareJid)); QStringList resources = m_xmppClient.rosterManager().getResources(bareJid); dlg.setFullName(m_vCardCache.getVCard(bareJid).fullName()); if(m_vCardCache.getVCard(bareJid).fullName().isEmpty()) dlg.setFullName(m_xmppClient.rosterManager().getRosterEntry(bareJid).name()); dlg.exec(); } void mainDialog::loadAccounts() { m_accountsCache.loadFromFile(); QStringList list = m_accountsCache.getBareJids(); QCompleter *completer = new QCompleter(list, this); completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion); completer->setCaseSensitivity(Qt::CaseInsensitive); ui->lineEdit_userName->setCompleter(completer); if(!list.isEmpty()) { ui->lineEdit_userName->setText(list.last()); QString passwd = m_accountsCache.getPassword(list.last()); ui->lineEdit_password->setText(passwd); if(!passwd.isEmpty()) ui->checkBox_rememberPasswd->setChecked(true); } } void mainDialog::userNameCompleter_activated(const QString& user) { QString passwd = m_accountsCache.getPassword(user); ui->lineEdit_password->setText(passwd); if(!passwd.isEmpty()) ui->checkBox_rememberPasswd->setChecked(true); } void mainDialog::addAccountToCache() { QString bareJid = ui->lineEdit_userName->text(); QString passwd = ui->lineEdit_password->text(); if(!ui->checkBox_rememberPasswd->isChecked()) passwd = ""; m_accountsCache.addAccount(bareJid, passwd); } void mainDialog::action_signOut() { m_xmppClient.disconnectFromServer(); // update widget m_statusWidget.setStatusText( presenceToStatusText(m_xmppClient.clientPresence())); } void mainDialog::action_quit() { m_xmppClient.disconnectFromServer(); QApplication::quit(); } void mainDialog::createTrayIconAndMenu() { bool check; Q_UNUSED(check); check = connect(&m_quitAction, SIGNAL(triggered()), SLOT(action_quit())); Q_ASSERT(check); check = connect(&m_signOutAction, SIGNAL(triggered()), SLOT(action_signOut())); Q_ASSERT(check); #ifndef QT_NO_SYSTEMTRAYICON m_trayIcon.setIcon(QIcon(":/icons/resource/icon.png")); check = connect(&m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(action_trayIconActivated(QSystemTrayIcon::ActivationReason))); Q_ASSERT(check); m_trayIconMenu.addAction(&m_signOutAction); m_trayIconMenu.addSeparator(); m_trayIconMenu.addAction(&m_quitAction); m_trayIcon.setContextMenu(&m_trayIconMenu); m_trayIcon.show(); #endif } void mainDialog::createSettingsMenu() { m_settingsMenu = new QMenu(ui->pushButton_settings); // ui->pushButton_settings->setMenu(m_settingsMenu); QAction* aboutDlg = new QAction("About", ui->pushButton_settings); connect(aboutDlg, SIGNAL(triggered()), SLOT(action_aboutDlg())); m_settingsMenu->addAction(aboutDlg); m_settingsMenu->addSeparator(); QAction* showXml = new QAction("Show XML Console...", ui->pushButton_settings); connect(showXml, SIGNAL(triggered()), SLOT(action_showXml())); m_settingsMenu->addAction(showXml); QMenu* viewMenu = new QMenu("View", ui->pushButton_settings); m_settingsMenu->addMenu(viewMenu); QAction* showOfflineContacts = new QAction("Show offline contacts", ui->pushButton_settings); showOfflineContacts->setCheckable(true); showOfflineContacts->setChecked(true); connect(showOfflineContacts, SIGNAL(triggered(bool)), &m_rosterItemSortFilterModel, SLOT(setShowOfflineContacts(bool))); viewMenu->addAction(showOfflineContacts); QAction* sortByName = new QAction("Sort by name", ui->pushButton_settings); sortByName->setCheckable(true); sortByName->setChecked(false); connect(sortByName, SIGNAL(triggered(bool)), &m_rosterItemSortFilterModel, SLOT(sortByName(bool))); viewMenu->addAction(sortByName); m_settingsMenu->addSeparator(); m_settingsMenu->addAction(&m_quitAction); } void mainDialog::closeEvent(QCloseEvent *event) { hide(); event->ignore(); } void mainDialog::action_trayIconActivated(QSystemTrayIcon::ActivationReason reason) { switch(reason) { case QSystemTrayIcon::Trigger: case QSystemTrayIcon::DoubleClick: show(); break; default: ; } } void mainDialog::action_addContact() { bool ok; QString bareJid = QInputDialog::getText(this, "Add a jabber contact", "Contact ID:", QLineEdit::Normal, "", &ok); if(!ok) return; if(!isValidBareJid(bareJid)) { QMessageBox::information(this, "Invalid ID", "Specified ID "+bareJid + " is invalid."); return; } if(ok && !bareJid.isEmpty()) { QXmppPresence subscribe; subscribe.setTo(bareJid); subscribe.setType(QXmppPresence::Subscribe); m_xmppClient.sendPacket(subscribe); } } void mainDialog::presenceReceived(const QXmppPresence& presence) { QString from = presence.from(); QString message; switch(presence.type()) { case QXmppPresence::Subscribe: { message = "%1 wants to subscribe"; int retButton = QMessageBox::question( this, "Contact Subscription", message.arg(from), QMessageBox::Yes, QMessageBox::No); switch(retButton) { case QMessageBox::Yes: { QXmppPresence subscribed; subscribed.setTo(from); subscribed.setType(QXmppPresence::Subscribed); m_xmppClient.sendPacket(subscribed); // reciprocal subscription QXmppPresence subscribe; subscribe.setTo(from); subscribe.setType(QXmppPresence::Subscribe); m_xmppClient.sendPacket(subscribe); } break; case QMessageBox::No: { QXmppPresence unsubscribed; unsubscribed.setTo(from); unsubscribed.setType(QXmppPresence::Unsubscribed); m_xmppClient.sendPacket(unsubscribed); } break; default: break; } return; } break; case QXmppPresence::Subscribed: message = "%1 accepted your request"; break; case QXmppPresence::Unsubscribe: message = "%1 unsubscribe"; break; case QXmppPresence::Unsubscribed: message = "%1 unsubscribed"; break; default: return; break; } if(message.isEmpty()) return; QMessageBox::information(this, "Contact Subscription", message.arg(from), QMessageBox::Ok); } void mainDialog::action_removeContact(const QString& bareJid) { if(!isValidBareJid(bareJid)) return; int answer = QMessageBox::question(this, "Remove contact", QString("Do you want to remove the contact %1").arg(bareJid), QMessageBox::Yes, QMessageBox::No); if(answer == QMessageBox::Yes) { QXmppRosterIq remove; remove.setType(QXmppIq::Set); QXmppRosterIq::Item itemRemove; itemRemove.setSubscriptionType(QXmppRosterIq::Item::Remove); itemRemove.setBareJid(bareJid); remove.addItem(itemRemove); m_xmppClient.sendPacket(remove); m_rosterItemModel.removeRosterEntry(bareJid); } } void mainDialog::errorClient(QXmppClient::Error error) { ui->label_throbber->hide(); showSignInPage(); switch(error) { case QXmppClient::SocketError: showLoginStatus("Socket error"); break; case QXmppClient::KeepAliveError: showLoginStatus("Keep alive error"); break; case QXmppClient::XmppStreamError: switch(m_xmppClient.xmppStreamError()) { case QXmppStanza::Error::NotAuthorized: showLoginStatus("Invalid password"); break; default: showLoginStatus("Stream error"); break; } break; default: break; } } void mainDialog::action_showXml() { m_consoleDlg.show(); } void mainDialog::addPhotoHash(QXmppPresence& pre) { QString clientBareJid = m_xmppClient.configuration().jidBare(); if(m_vCardCache.isVCardAvailable(clientBareJid)) { QByteArray hash = m_vCardCache.getPhotoHash(clientBareJid); if(hash.isEmpty()) pre.setVCardUpdateType(QXmppPresence::VCardUpdateNoPhoto); else pre.setVCardUpdateType(QXmppPresence::VCardUpdateValidPhoto); pre.setPhotoHash(hash); } else { pre.setVCardUpdateType(QXmppPresence::VCardUpdateNone); pre.setPhotoHash(QByteArray()); } } void mainDialog::action_aboutDlg() { aboutDialog abtDlg(this); abtDlg.exec(); } void mainDialog::action_settingsPressed() { m_settingsMenu->exec(ui->pushButton_settings->mapToGlobal(QPoint(0, ui->pushButton_settings->height()))); } qxmpp-0.9.3/examples/GuiClient/mainDialog.h000066400000000000000000000070521263006255200206130ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 MAINDIALOG_H #define MAINDIALOG_H #include #include #include #include #include "rosterItemModel.h" #include "rosterItemSortFilterProxyModel.h" #include "statusWidget.h" #include "vCardCache.h" #include "capabilitiesCache.h" #include "accountsCache.h" #include "xmlConsoleDialog.h" #include "QXmppClient.h" class chatDialog; class QKeyEvent; namespace Ui { class mainDialogClass; } class mainDialog : public QDialog { Q_OBJECT public: mainDialog(QWidget *parent = 0); protected: void keyPressEvent(QKeyEvent*); void closeEvent(QCloseEvent* event); private slots: void rosterChanged(const QString& bareJid); void rosterReceived(); void presenceChanged(const QString&, const QString&); void filterChanged(const QString& filter); void showChatDialog(const QString& bareJid); void messageReceived(const QXmppMessage& msg); void statusTextChanged(const QString&); void presenceTypeChanged(QXmppPresence::Type); void presenceStatusTypeChanged(QXmppPresence::AvailableStatusType); void signIn(); void cancelSignIn(); void showSignInPage(); void showSignInPageAfterUserDisconnection(); void showRosterPage(); void startConnection(); void updateStatusWidget(); void showLoginStatusWithProgress(const QString& msg); void showLoginStatus(const QString& msg); void showLoginStatusWithCounter(const QString& msg, int time); void updateVCard(const QString& bareJid); void avatarChanged(const QImage&); void showProfile(const QString& bareJid); void userNameCompleter_activated(const QString&); void addAccountToCache(); void presenceReceived(const QXmppPresence&); void errorClient(QXmppClient::Error); void action_addContact(); void action_removeContact(const QString& bareJid); void action_signOut(); void action_quit(); void action_trayIconActivated(QSystemTrayIcon::ActivationReason reason); void action_showXml(); void action_aboutDlg(); void action_settingsPressed(); private: void loadAccounts(); void createTrayIconAndMenu(); void createSettingsMenu(); void addPhotoHash(QXmppPresence&); chatDialog* getChatDialog(const QString& bareJid); Ui::mainDialogClass* ui; QXmppClient m_xmppClient; rosterItemModel m_rosterItemModel; rosterItemSortFilterProxyModel m_rosterItemSortFilterModel; statusWidget m_statusWidget; vCardCache m_vCardCache; capabilitiesCache m_capabilitiesCache; accountsCache m_accountsCache; // map of bare jids and respective chatdlg QMap m_chatDlgsList; #ifndef QT_NO_SYSTEMTRAYICON QSystemTrayIcon m_trayIcon; QMenu m_trayIconMenu; #endif QAction m_quitAction; QAction m_signOutAction; xmlConsoleDialog m_consoleDlg; QMenu* m_settingsMenu; }; #endif // MAINDIALOG_H qxmpp-0.9.3/examples/GuiClient/mainDialog.ui000066400000000000000000000254011263006255200207770ustar00rootroot00000000000000 mainDialogClass true 0 0 236 484 QXmpp :/icons/resource/icon.png:/icons/resource/icon.png 6 0 6 0 4 0 0 true QAbstractItemView::NoEditTriggers QAbstractItemView::ScrollPerPixel 29 29 29 29 :/icons/resource/addButton.png:/icons/resource/addButton.png 29 29 Qt::Horizontal 40 20 29 29 29 29 :/icons/resource/settingsButton.png:/icons/resource/settingsButton.png 29 29 true 20 20 Qt::Vertical 20 40 Login: QLineEdit::Password Remember password Qt::Horizontal 40 20 Sign in Cancel Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 0 Qt::Horizontal 40 20 movie 0 0 0 35 Qt::Horizontal 40 20 Qt::Vertical 20 70 rosterListView QListView
rosterListView.h
searchLineEdit QLineEdit
searchLineEdit.h
signInStatusLabel QLabel
signInStatusLabel.h
qxmpp-0.9.3/examples/GuiClient/profileDialog.cpp000066400000000000000000000132711263006255200216620ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "profileDialog.h" #include "ui_profileDialog.h" #include "utils.h" #include "QXmppClient.h" #include "QXmppVersionIq.h" #include "QXmppVersionManager.h" #include "QXmppRosterManager.h" #include "QXmppUtils.h" #include "QXmppEntityTimeManager.h" #include "QXmppEntityTimeIq.h" #include "QXmppConstants.h" profileDialog::profileDialog(QWidget *parent, const QString& bareJid, QXmppClient& client, capabilitiesCache& caps) : QDialog(parent, Qt::WindowTitleHint|Qt::WindowSystemMenuHint), ui(new Ui::profileDialog), m_bareJid(bareJid), m_xmppClient(client), m_caps(caps) { bool check; Q_UNUSED(check); ui->setupUi(this); check = connect(&m_xmppClient.versionManager(), SIGNAL(versionReceived(QXmppVersionIq)), SLOT(versionReceived(QXmppVersionIq))); Q_ASSERT(check); QXmppEntityTimeManager* timeManager = m_xmppClient.findExtension(); if(timeManager) { check = connect(timeManager, SIGNAL(timeReceived(QXmppEntityTimeIq)), SLOT(timeReceived(QXmppEntityTimeIq))); Q_ASSERT(check); } QStringList resources = m_xmppClient.rosterManager().getResources(bareJid); foreach(QString resource, resources) { QString jid = bareJid + "/" + resource; m_xmppClient.versionManager().requestVersion(jid); if(timeManager) timeManager->requestTime(jid); } updateText(); } profileDialog::~profileDialog() { delete ui; } void profileDialog::setAvatar(const QImage& image) { ui->label_avatar->setPixmap(QPixmap::fromImage(image)); } void profileDialog::setBareJid(const QString& bareJid) { ui->label_jid->setText(bareJid); setWindowTitle(bareJid); } void profileDialog::setFullName(const QString& fullName) { if(fullName.isEmpty()) ui->label_fullName->hide(); else ui->label_fullName->show(); ui->label_fullName->setText(fullName); } void profileDialog::setStatusText(const QString& status) { ui->label_status->setText(status); } void profileDialog::versionReceived(const QXmppVersionIq& ver) { m_versions[QXmppUtils::jidToResource(ver.from())] = ver; if(ver.type() == QXmppIq::Result) updateText(); } void profileDialog::timeReceived(const QXmppEntityTimeIq& time) { m_time[QXmppUtils::jidToResource(time.from())] = time; if(time.type() == QXmppIq::Result) updateText(); } void profileDialog::updateText() { QStringList resources = m_xmppClient.rosterManager().getResources(m_bareJid); QString statusText; for(int i = 0; i < resources.count(); ++i) { QString resource = resources.at(i); statusText += "Resource: " + resource; statusText += "
"; QXmppPresence presence = m_xmppClient.rosterManager().getPresence(m_bareJid, resource); statusText += "Status: " + presenceToStatusText(presence); statusText += "
"; if(m_versions.contains(resource)) { statusText += "Software: " + QString("%1 %2 %3"). arg(m_versions[resource].name()). arg(m_versions[resource].version()). arg(m_versions[resource].os()); statusText += "
"; } if(m_time.contains(resource)) { statusText += "Time: " + QString("utc=%1 [tzo=%2]"). arg(m_time[resource].utc().toString()). arg(QXmppUtils::timezoneOffsetToString(m_time[resource].tzo())); statusText += "
"; } statusText += getCapability(resource); if(i < resources.count() - 1) // skip for the last item statusText += "
"; } setStatusText(statusText); } QString profileDialog::getCapability(const QString& resource) { QMap presences = m_xmppClient.rosterManager(). getAllPresencesForBareJid(m_bareJid); QXmppPresence& pre = presences[resource]; QString nodeVer; QStringList resultFeatures; QStringList resultIdentities; QString node = pre.capabilityNode(); QString ver = pre.capabilityVer().toBase64(); QStringList exts = pre.capabilityExt(); nodeVer = node + "#" + ver; if(m_caps.isCapabilityAvailable(nodeVer)) { resultFeatures << m_caps.getFeatures(nodeVer); resultIdentities << m_caps.getIdentities(nodeVer); } foreach(QString ext, exts) { nodeVer = node + "#" + ext; if(m_caps.isCapabilityAvailable(nodeVer)) { resultFeatures << m_caps.getFeatures(nodeVer); resultIdentities << m_caps.getIdentities(nodeVer); } } resultIdentities.removeDuplicates(); resultFeatures.removeDuplicates(); QString result; result += "Disco Identities:
"; result += resultIdentities.join("
"); result += "
"; result += "Disco Features:
"; result += resultFeatures.join("
"); result += "
"; return result; } qxmpp-0.9.3/examples/GuiClient/profileDialog.h000066400000000000000000000035411263006255200213260ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 PROFILEDIALOG_H #define PROFILEDIALOG_H #include #include #include "capabilitiesCache.h" namespace Ui { class profileDialog; } class QXmppClient; class QXmppVersionIq; class QXmppEntityTimeIq; class profileDialog : public QDialog { Q_OBJECT public: explicit profileDialog(QWidget *parent, const QString& bareJid, QXmppClient& client, capabilitiesCache& caps); ~profileDialog(); void setClientRef(QXmppClient& m_xmppClient); void setAvatar(const QImage&); void setBareJid(const QString&); void setFullName(const QString&); void setStatusText(const QString&); private slots: void versionReceived(const QXmppVersionIq&); void timeReceived(const QXmppEntityTimeIq&); private: void updateText(); QString getCapability(const QString& resource); private: Ui::profileDialog *ui; QString m_bareJid; QXmppClient& m_xmppClient; // reference to the active QXmppClient (No ownership) capabilitiesCache& m_caps; // reference to the active QXmppClient (No ownership) QMap m_versions; QMap m_time; }; #endif // PROFILEDIALOG_H qxmpp-0.9.3/examples/GuiClient/profileDialog.ui000066400000000000000000000132501263006255200215120ustar00rootroot00000000000000 profileDialog 0 0 309 209 Profile true 6 QFrame::NoFrame true Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 0 0 297 168 6 0 QLayout::SetFixedSize 0 0 96 96 96 96 :/icons/resource/avatar.png true Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::Vertical 0 0 TextLabel TextLabel TextLabel true Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse Qt::Vertical 0 0 Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() profileDialog accept() 343 215 301 191 buttonBox rejected() profileDialog close() 237 216 230 172 qxmpp-0.9.3/examples/GuiClient/resource/000077500000000000000000000000001263006255200202215ustar00rootroot00000000000000qxmpp-0.9.3/examples/GuiClient/resource/addButton.png000066400000000000000000000005071263006255200226550ustar00rootroot00000000000000PNG  IHDRr ߔsRGBbKGD pHYs  tIME . ^iTXtCommentCreated with GIMPd.eIDATHc``FR58m```P{`]?)Yp29e````"3T1-c!;6-,E'c( x  ͇L$FRBw ag``A 'AJ-:>"@NY`P ݍj7nIENDB`qxmpp-0.9.3/examples/GuiClient/resource/ajax-loader.gif000066400000000000000000000062101263006255200230760ustar00rootroot00000000000000GIF89a Ƅ666VVV似! NETSCAPE2.0!Created with ajaxload.info! , IiabK$F RAT,2S*05//mp!z0;$0C.I*!HC(A@o!39T5\8) `dwxG=Y gwHbvA=0 V\\; ;H0t%HsrY'e$"\#E1CnĎ~J,,AaUw^4I%Pu Q33{0i1TGgwy}%%'R  = 3G%p0 JRo5Ȇ0IĦmykxT_}(^yKs>i_%n=q4e-M¤D! , I)*')Ed]PR A:!zrbw %6"G(d$["JFhaQP`p%†/BFP\cU ?TtW/pG&OtDa_sylD'M q tc b2DM : d% 4%s) uE3 YUtږD$JiM^%o/rvl9'L;99% i9 C "B BDs ^Xf}$P {L?P O4 E咛V$dJ#)pV$! , IiRͧ"Jd] RZN*P*;$P{*N\EА!1UO2D _r6Ib H8 B; "'ZtbK#C'Kw}?Kiz6:xKAC&}9tz\ \D5;x Qd( KW  MBIڈM=ˤs⸽8DaJ`@LG! , IiRͧ"Jd] RZN*P*;$P{*N\EА!1UO2D _r6Ib H8 B; "'ZtbK#C'KGziz68}z~%XK9:0}% tz\Blc LbQ   lj ųKň x(țPX ,ւ|/"! , IiRͧ"Jd] RZN*P*;$P{*N\EА!1UO2D _r6Ib H8 B; "'ZtbK#C'KGziz68}z~%:A/ C} u\ h}b D]=  V)  ڊ9CDK Ku *00StD! , IiRͧ"Jd] RZN*P*;$P{*N\EА!1UO2D _r6Ib H8 B; "'ZtbK#C'KGz z5 C: A/ C}u\ Eh}b6[=Wx&)I9Ԭ@oCT?Kd]B76ЫD! , IiRͧ"Jd] RZN*P*;$P{*N\EА!1UO2D _r6I ƀH03hոaj U {CIkmbK#cK8 {a8nV:/q:M Cu~Ehk6 [_6P.]6!)V! , IiRͧ"Jd]U RZN JjN2sK6 dI)  LHWG 6 KX젱.6d~zhuur/6 X5I;_t O#E {O9V94;VC/ 6Ø~*'MonbX:~]+V*mK_OrKN@.d~qЦDB֋ 5D;qxmpp-0.9.3/examples/GuiClient/resource/avatar.png000066400000000000000000000017011263006255200222040ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME2} tEXtCommentCreated with GIMPWIDATXWɶ@=0$y9._x{@ $< =@ =rnW|4|q@h?f iνi[wI>#}^f'{+Xg4 0DZߣ,K^{d}R;3cc .+y ġZa(H>{v ?gXkl?A.l+Qq`#_og87h9ã fOKӬz~"mnǎ1֚ȡ!xcH|\?q D!jв ƁI8 iwG ,2[PΙn&>P(R 4癉d~zyY%p/d( c' %k;݉@ltj8@8LC7 BTUXBPL$-@5qF}fq}X`;K^f))mkƐ)(R3Sfxin;gWr98uܵ!x}Wj½vx;ۡ!rSbAc=lMؕꪄgc`uZ8#iGZ4] -ʲ@$ ]@ 0+&1F'T;:  񰇔z C.p)R ~M 4pM t}@m,5^) cxm&4څ||έko⣔ *%yk{lq-Y dBPW3IENDB`qxmpp-0.9.3/examples/GuiClient/resource/downArrow.png000066400000000000000000000003151263006255200227100ustar00rootroot00000000000000PNG  IHDRB%}sRGBbKGD pHYs  tIME 7*tEXtCommentCreated with GIMPW(IDATuA 0 Lgw$YlAM/)DIENDB`qxmpp-0.9.3/examples/GuiClient/resource/gray.png000066400000000000000000000005251263006255200216730ustar00rootroot00000000000000PNG  IHDR 2ϽsRGBbKGD pHYs  tIME-tEXtCommentCreated with GIMPWIDATӍM @ Fxzz"x^] ]aH7߃@ /$ 0 'z#Ћ 1 \yO+"SbI, ^ˀfNF Z  r pO>6@t >g"P,Su9~Nu)Cߪ YĹ+ n :b f <j!Btպ ')!/ k ~|~r{ x;7ۇg0ͷ j7܀^L~c ˀAmw2,}/ o I-ϯrym`bamifXz \P" 4PFL^XBE+Cϊ+ kp%e8 >V "Qw63+bd&d<R̈́ UsKIENDB`qxmpp-0.9.3/examples/GuiClient/resource/icon.xcf000066400000000000000000000046241263006255200216610ustar00rootroot00000000000000gimp xcf file BB&G gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) R  New Layer#4b     j ~ 333ZZ!ETK82  New Layer     ~  &&&RR&&&&RR&&  New Layer#2     %T h x::cMMMM  New Layer#5     #  :::MMMM  New Layer#1       :$$$:$$$$:MMMM Selection Mask  &  : JYYYYYYYYqxmpp-0.9.3/examples/GuiClient/resource/orange.png000066400000000000000000000005311263006255200222010ustar00rootroot00000000000000PNG  IHDR 2ϽsRGBbKGD pHYs  tIME0*tEXtCommentCreated with GIMPWIDATӅ=JabؤHm<{rT9B`c%Ft?6၁g`,UVbLe SNh?خy8>kyu{8{ 햷 ?o9cf7E?;TYeH% ̢YG]D'Z8HIENDB`qxmpp-0.9.3/examples/GuiClient/resource/red.png000066400000000000000000000005471263006255200215070ustar00rootroot00000000000000PNG  IHDR 2ϽsRGBbKGD pHYs  tIME$J'tEXtCommentCreated with GIMPWIDATӅ= @]D+%X%:1g(E%Bf烁f7 a="`&e0O2(1M%I̬l5ÈhS?T3rZN q? (h֙Z#hGw(UE]TJ]qZckSÔ&5@sh<L:s"IENDB`qxmpp-0.9.3/examples/GuiClient/resource/redred.png000066400000000000000000000011021263006255200221660ustar00rootroot00000000000000PNG  IHDR--:sRGBbKGD pHYs  tIME ;3ytEXtCommentCreated with GIMPWIDATX햱@N!vAiv>C. ؋ &ML#)抹K8av2; C?7CKڲVU8_VU~JTtpG>Pq~gQ}Yk) 4 LlhamɄL{X7@Y72R2]NX^/.\}Od6%m6ٌA8-wip-([`c |5=X.n6\Oj6lt=^5 (zCX$uGgURV444444444444444444444OUڝB2IENDB`qxmpp-0.9.3/examples/GuiClient/resource/searchIcon.png000066400000000000000000000013331263006255200230050ustar00rootroot00000000000000PNG  IHDRVΎWsRGBbKGD pHYs  tIME 3:{&tEXtCommentCreated with GIMPW6IDAT8˭KSq?;S7<嶓njȄ"n?nq7ݔd҅g3M63gmGC(/>ZV?Gl-eIOCO[1Yv̮319-zw8ͳOQq~0@zS #'235Nz%NLL!I".  @PCH>6V-L,K֊/Ht1OGŽ#OPAAq,-f*pbhiݠہ Y>Pل88mutHqBaӉ " P)Z(sfB wD ԝ5YAF2KNZD `PW@ F]Y28wQv_EI,o_?ߋy?u>~K-U;( i+ ]0A|y "7 -D^f^V5g@\qJok=Tw}0W16>ǣ b$[Í-{?I_ݦZIENDB`qxmpp-0.9.3/examples/GuiClient/resource/settingsButton.png000066400000000000000000000030611263006255200237630ustar00rootroot00000000000000PNG  IHDR[HtEXtSoftwareAdobe ImageReadyqe<fiTXtXML:com.adobe.xmp UGaIDATxb?e,$ULXʙXb{oJeY@D?־{22gZW?|tp,m n<IQ| T>0nGQ+ήqZTaF03e+..CqW42W0F:v쥍b?(0}bbdx ?) +( F #}-GěS`6VFF`b x),,s37N^켂8?`ç/em[)M JR<_&&v`1 Ys{K*R>f梍Wm<x>~G__?l}qT5%L8ISm68d_߀~Z ״tjoX}-$ .lJo?srbQ9#Mj@ 3vSFPFg 'E P0R;&.d~J+\icSK @Aq?.uMQe]ʤIENDB`qxmpp-0.9.3/examples/GuiClient/resources.qrc000066400000000000000000000010201263006255200211040ustar00rootroot00000000000000 resource/green.png resource/orange.png resource/red.png resource/gray.png resource/avatar.png resource/searchIcon.png resource/downArrow.png resource/ajax-loader.gif resource/icon.png resource/settingsButton.png resource/addButton.png qxmpp-0.9.3/examples/GuiClient/rosterItem.cpp000066400000000000000000000133761263006255200212450ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "rosterItem.h" #include rosterItem::rosterItem(const QString& bareJid) { setData(bareJid, rosterItem::BareJid); setData("Offline", rosterItem::StatusText); setAvatar(QImage(":/icons/resource/avatar.png")); setIcon(QIcon(":/icons/resource/gray.png")); } void rosterItem::setName(const QString& name) { setText(name); } QString rosterItem::getName() { return text(); } void rosterItem::setPresence(const QXmppPresence &presence) { // determine status text QString statusText = presence.statusText(); if (statusText.isEmpty()) { if(presence.type() == QXmppPresence::Available) statusText = "Available"; else if(presence.type() == QXmppPresence::Unavailable) statusText = "Offline"; } // store data setData(statusText, rosterItem::StatusText); setData(static_cast(presence.type()), PresenceType); setData(static_cast(presence.availableStatusType()), StatusType); // update icon QString icon; if (presence.type() == QXmppPresence::Available) { switch (presence.availableStatusType()) { case QXmppPresence::Online: case QXmppPresence::Chat: icon = "green"; break; case QXmppPresence::Away: case QXmppPresence::XA: icon = "orange"; break; case QXmppPresence::DND: icon = "red"; break; case QXmppPresence::Invisible: icon = "gray"; break; } } else { icon = "gray"; } if (!icon.isEmpty()) setIcon(QIcon(":/icons/resource/"+icon+".png")); } void rosterItem::setAvatar(const QImage& image) { setData(QVariant(image), rosterItem::Avatar); } QImage rosterItem::getAvatar() { return qvariant_cast(data(rosterItem::Avatar)); } rosterItemDelegate::rosterItemDelegate() { } QSize rosterItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex & index) const { Q_UNUSED(option); Q_UNUSED(index); return QSize(44, 36); } void rosterItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { painter->save(); painter->setRenderHint(QPainter::TextAntialiasing); QVariant value = index.data(Qt::DecorationRole); QColor selectedBg(60, 140, 222); QColor alternateBg(239, 245, 254); QColor selectedText(Qt::white); QColor nameTextColor(Qt::black); QColor statusTextColor(Qt::darkGray); QPixmap pixmap; if(value.type() == QVariant::Icon) { QIcon icon = qvariant_cast(value); pixmap = icon.pixmap(QSize(16, 16), QIcon::Normal, QIcon::On); } QPen penDivision; // if(index.row() % 2) // painter->fillRect(option.rect, alternateBg); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, selectedBg); // painter->fillRect(option.rect, option.palette.highlight()); // penDivision.setColor(option.palette.highlight().color()); penDivision.setColor(selectedBg); nameTextColor = selectedText; statusTextColor = selectedText; } else { penDivision.setColor(QColor(244, 244, 244)); } QRect rect = option.rect; rect.setWidth(pixmap.width()); rect.setHeight(pixmap.height()); rect.moveTop(rect.y() + (option.rect.height() - pixmap.height())/2); rect.moveLeft(rect.left() + 2); painter->drawPixmap(rect, pixmap); rect = option.rect; rect.setLeft(rect.x() + pixmap.width() + 8); rect.moveTop(rect.y() + 3); QFont font; painter->setFont(font); painter->setPen(nameTextColor); if(!index.data(Qt::DisplayRole).toString().isEmpty()) painter->drawText(rect, index.data(Qt::DisplayRole).toString()); else painter->drawText(rect, index.data(rosterItem::BareJid).toString()); painter->setPen(statusTextColor); rect.setTop(rect.y() + rect.height()/2); rect.moveTop(rect.y() - 3); QString statusText = index.data(rosterItem::StatusText).toString(); QFontMetrics fontMetrics(font); statusText = fontMetrics.elidedText(statusText, Qt::ElideRight, rect.width() - 34); painter->drawText(rect, statusText); penDivision.setWidth(0); painter->setPen(penDivision); rect = option.rect; QPoint left = rect.bottomLeft(); left.setX(left.x() + 4); QPoint right = rect.bottomRight(); right.setX(right.x() - 4); painter->drawLine(left, right); QImage image; value = index.data(rosterItem::Avatar); if(value.type() == QVariant::Image) { image = qvariant_cast(value); } pixmap = QPixmap(":/icons/resource/avatar.png"); rect = option.rect; rect.setWidth(pixmap.width()); rect.setHeight(pixmap.height()); rect.moveTop(rect.y() + (option.rect.height() - pixmap.height())/2); rect.moveLeft(option.rect.x() + option.rect.width() - pixmap.width() - 2); // if(image.isNull()) // painter->drawPixmap(rect, pixmap); // else painter->drawImage(rect, image); painter->restore(); } qxmpp-0.9.3/examples/GuiClient/rosterItem.h000066400000000000000000000030501263006255200206760ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 ROSTERITEM_H #define ROSTERITEM_H #include #include #include #include "QXmppPresence.h" class rosterItem : public QStandardItem { public: enum userRoles { StatusText = Qt::UserRole + 2, StatusType, PresenceType, BareJid, Avatar }; rosterItem(const QString& bareJid); void setAvatar(const QImage& image); void setPresence(const QXmppPresence &presence); void setName(const QString& name); QImage getAvatar(); QString getName(); }; class rosterItemDelegate : public QItemDelegate { public: rosterItemDelegate(); QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; }; #endif // ROSTERITEM_H qxmpp-0.9.3/examples/GuiClient/rosterItemModel.cpp000066400000000000000000000050301263006255200222120ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "rosterItemModel.h" rosterItemModel::rosterItemModel(QObject* parent) : QStandardItemModel(parent) { // addRosterItemIfDontExist("jkhjkhkhkhk"); // addRosterItemIfDontExist("uuuu"); // addRosterItemIfDontExist("kkkkkkk"); // addRosterItemIfDontExist("jjjjjjjj"); } rosterItem* rosterItemModel::getRosterItemFromBareJid(const QString& bareJid) { if(m_jidRosterItemMap.contains(bareJid)) return m_jidRosterItemMap[bareJid]; else return 0; } rosterItem* rosterItemModel::getOrCreateItem(const QString& bareJid) { if(m_jidRosterItemMap.contains(bareJid)) { return m_jidRosterItemMap[bareJid]; } else { rosterItem* item = new rosterItem(bareJid); m_jidRosterItemMap[bareJid] = item; appendRow(item); return item; } } void rosterItemModel::updatePresence(const QString& bareJid, const QMap& presences) { rosterItem *item = getOrCreateItem(bareJid); if (!presences.isEmpty()) item->setPresence(*presences.begin()); else item->setPresence(QXmppPresence(QXmppPresence::Unavailable)); } void rosterItemModel::updateRosterEntry(const QString& bareJid, const QXmppRosterIq::Item& rosterEntry) { getOrCreateItem(bareJid)->setName(rosterEntry.name()); } void rosterItemModel::updateAvatar(const QString& bareJid, const QImage& image) { getOrCreateItem(bareJid)->setAvatar(image); } void rosterItemModel::updateName(const QString& bareJid, const QString& name) { if (!name.isEmpty()) getOrCreateItem(bareJid)->setName(name); } void rosterItemModel::clear() { QStandardItemModel::clear(); m_jidRosterItemMap.clear(); } void rosterItemModel::removeRosterEntry(const QString& bareJid) { rosterItem* item = getRosterItemFromBareJid(bareJid); if(item) { removeRow(item->row()); } } qxmpp-0.9.3/examples/GuiClient/rosterItemModel.h000066400000000000000000000030641263006255200216640ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 ROSTERITEMMODEL_H #define ROSTERITEMMODEL_H #include #include "rosterItem.h" #include "QXmppRosterManager.h" #include "QXmppPresence.h" class rosterItemModel : public QStandardItemModel { public: rosterItemModel(QObject* parent); rosterItem* getRosterItemFromBareJid(const QString& bareJid); void updatePresence(const QString& bareJid, const QMap& presences); void updateRosterEntry(const QString& bareJid, const QXmppRosterIq::Item& rosterEntry); void updateAvatar(const QString& bareJid, const QImage& image); void updateName(const QString& bareJid, const QString& name); void removeRosterEntry(const QString& bareJid); void clear(); private: rosterItem* getOrCreateItem(const QString& bareJid); QMap m_jidRosterItemMap; }; #endif // ROSTERITEMMODEL_H qxmpp-0.9.3/examples/GuiClient/rosterItemSortFilterProxyModel.cpp000066400000000000000000000070371263006255200253030ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "rosterItemSortFilterProxyModel.h" #include "rosterItem.h" #include "utils.h" rosterItemSortFilterProxyModel::rosterItemSortFilterProxyModel(QObject* parent): QSortFilterProxyModel(parent), m_showOfflineContacts(true), m_sortByName(false) { setDynamicSortFilter(true); setFilterRole(Qt::DisplayRole); setFilterCaseSensitivity(Qt::CaseInsensitive); } bool rosterItemSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { if(m_sortByName) { int compare = left.data().toString().compare(right.data().toString(), Qt::CaseInsensitive); if(compare < 0) return true; else return false; } else { int leftPresenceType = sourceModel()->data(left, rosterItem::PresenceType).toInt(); int leftStatusType = sourceModel()->data(left, rosterItem::StatusType).toInt(); int rightPresenceType = sourceModel()->data(right, rosterItem::PresenceType).toInt(); int rightStatusType = sourceModel()->data(right, rosterItem::StatusType).toInt(); if(leftPresenceType == rightPresenceType) { if(leftStatusType == rightStatusType) { // based on display text int compare = left.data().toString().compare(right.data().toString(), Qt::CaseInsensitive); if(compare < 0) return true; else return false; } else { return comparisonWeightsPresenceStatusType(static_cast(leftStatusType)) < comparisonWeightsPresenceStatusType(static_cast(rightStatusType)); } } else return comparisonWeightsPresenceType(static_cast(leftPresenceType)) < comparisonWeightsPresenceType(static_cast(rightPresenceType)); } } bool rosterItemSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { if(!filterRegExp().isEmpty()) return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); if(m_showOfflineContacts) return true; QModelIndex index = sourceModel()->index(source_row, 0, source_parent); int presenceType = sourceModel()->data(index, rosterItem::PresenceType).toInt(); if(presenceType == QXmppPresence::Available) return true; else return false; } void rosterItemSortFilterProxyModel::setShowOfflineContacts(bool showOfflineContacts) { m_showOfflineContacts = showOfflineContacts; invalidateFilter(); } void rosterItemSortFilterProxyModel::sortByName(bool sortByName) { m_sortByName = sortByName; invalidate(); } qxmpp-0.9.3/examples/GuiClient/rosterItemSortFilterProxyModel.h000066400000000000000000000024321263006255200247420ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 ROSTERITEMSORTFILTERPROXYMODEL_H #define ROSTERITEMSORTFILTERPROXYMODEL_H #include class rosterItemSortFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT public: rosterItemSortFilterProxyModel(QObject* parent = 0); public slots: void setShowOfflineContacts(bool); void sortByName(bool); private: bool lessThan(const QModelIndex &left, const QModelIndex &right) const; bool filterAcceptsRow(int, const QModelIndex&) const; bool m_showOfflineContacts; bool m_sortByName; }; #endif // ROSTERITEMSORTFILTERPROXYMODEL_H qxmpp-0.9.3/examples/GuiClient/rosterListView.cpp000066400000000000000000000064601263006255200221110ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "rosterListView.h" #include "rosterItem.h" #include #include #include rosterListView::rosterListView(QWidget* parent) : QListView(parent) , m_chat("Chat", this) , m_profile("View Profile", this) , m_removeContact("Remove", this) { bool check; Q_UNUSED(check); check = connect(this, SIGNAL(pressed(QModelIndex)), this, SLOT(mousePressed(QModelIndex))); Q_ASSERT(check); check = connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(doubleClicked(QModelIndex))); Q_ASSERT(check); check = connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(clicked(QModelIndex))); Q_ASSERT(check); check = connect(&m_chat, SIGNAL(triggered()), this, SLOT(showChatDialog_helper())); Q_ASSERT(check); check = connect(&m_profile, SIGNAL(triggered()), this, SLOT(showProfile_helper())); Q_ASSERT(check); check = connect(&m_removeContact, SIGNAL(triggered()), this, SLOT(removeContact_helper())); Q_ASSERT(check); } bool rosterListView::event(QEvent* e) { return QListView::event(e); } void rosterListView::mousePressed(const QModelIndex& index) { if(QApplication::mouseButtons() == Qt::RightButton) { QString bareJid = index.data().toString(); QMenu menu(this); menu.addAction(&m_chat); menu.setDefaultAction(&m_chat); menu.addAction(&m_profile); menu.addAction(&m_removeContact); menu.exec(QCursor::pos()); } } void rosterListView::doubleClicked(const QModelIndex& index) { Q_UNUSED(index); m_chat.trigger(); } void rosterListView::clicked(const QModelIndex& index) { Q_UNUSED(index); } QString rosterListView::selectedBareJid() { if(selectedIndexes().size() > 0) return selectedIndexes().at(0).data(rosterItem::BareJid).toString(); else return ""; } void rosterListView::showChatDialog_helper() { QString bareJid = selectedBareJid(); if(!bareJid.isEmpty()) emit showChatDialog(bareJid); } void rosterListView::showProfile_helper() { QString bareJid = selectedBareJid(); if(!bareJid.isEmpty()) emit showProfile(bareJid); } void rosterListView::keyPressEvent(QKeyEvent* event1) { if(event1->key() == Qt::Key_Return) { showChatDialog_helper(); } QListView::keyPressEvent(event1); } void rosterListView::removeContact_helper() { QString bareJid = selectedBareJid(); if(!bareJid.isEmpty()) emit removeContact(bareJid); } qxmpp-0.9.3/examples/GuiClient/rosterListView.h000066400000000000000000000030331263006255200215470ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 ROSTERLISTVIEW_H #define ROSTERLISTVIEW_H #include #include class rosterListView : public QListView { Q_OBJECT public: rosterListView(QWidget* parent = 0); bool event(QEvent* e); public slots: void mousePressed(const QModelIndex& index); void doubleClicked(const QModelIndex& index); void clicked(const QModelIndex& index); private slots: void showChatDialog_helper(); void showProfile_helper(); void removeContact_helper(); protected: void keyPressEvent(QKeyEvent*); signals: void showChatDialog(const QString& bareJid); void showProfile(const QString& bareJid); void removeContact(const QString& bareJid); private: QString selectedBareJid(); private: QAction m_chat; QAction m_profile; QAction m_removeContact; }; #endif // ROSTERLISTVIEW_H qxmpp-0.9.3/examples/GuiClient/searchLineEdit.cpp000066400000000000000000000043011263006255200217570ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "searchLineEdit.h" searchLineEdit::searchLineEdit(QWidget* parent):QLineEdit(parent) { setMinimumSize(QSize(20, 24)); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); setStyleSheet(":enabled { padding-right: 20px; padding-left: 20px }"); clearButton = new searchClearButton(this); clearButton->setVisible(true); clearButton->setCursor(Qt::ArrowCursor); clearButton->setToolTip("Clear"); connect(clearButton, SIGNAL(clicked()), this, SLOT(clear())); } void searchLineEdit::paintEvent(QPaintEvent *e) { QLineEdit::paintEvent(e); QPainter painter(this); QImage image(":/icons/resource/searchIcon.png"); QRectF target(image.rect()); target.moveCenter(QPointF(target.center().x()+2, target.center().y()+3)); painter.drawImage(target, image, image.rect()); if (text().length() == 0 && (!hasFocus()) ) { painter.setPen(Qt::gray); QRect r = rect(); painter.drawText(24, r.height()/2+4, "Search Contacts"); } if(text().isEmpty()) clearButton->setVisible(false); else clearButton->setVisible(true); } void searchLineEdit::resizeEvent(QResizeEvent*) { clearButton->setParent(this); clearButton->setGeometry(QRect(width()-23, 0, 24, 24)); } void searchLineEdit::moveEvent(QMoveEvent*) { clearButton->setParent(this); clearButton->setGeometry(QRect(width()-23, 1, 24, 24)); } qxmpp-0.9.3/examples/GuiClient/searchLineEdit.h000066400000000000000000000042401263006255200214260ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 SEARCHLINEEDIT_H #define SEARCHLINEEDIT_H #include #include #include class searchClearButton : public QPushButton { Q_OBJECT public: searchClearButton(QWidget *w) : QPushButton(w) { setMinimumSize(24, 24); setFixedSize(24, 24); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } void paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter painter(this); int height = parentWidget()->geometry().height(); int width = height; //parentWidget()->geometry().width(); painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(Qt::white); float penwidth = isDown() ? 1.2 : underMouse() ? 1.6 : 1.2; painter.setBrush(Qt::red); //painter.drawEllipse(4, 4, width - 8, height - 8); QPen pen; pen.setWidthF(penwidth); pen.setColor(Qt::black); painter.setPen(pen); int border = 7; painter.drawLine(border, border, width - border, height - border); painter.drawLine(border, height - border, width - border, border); } }; class searchLineEdit : public QLineEdit { public: searchLineEdit(QWidget* parent = 0); protected: virtual void paintEvent(QPaintEvent* e); virtual void resizeEvent(QResizeEvent*); virtual void moveEvent(QMoveEvent*); private: QPushButton *clearButton; }; #endif // SEARCHLINEEDIT_H qxmpp-0.9.3/examples/GuiClient/signInStatusLabel.cpp000066400000000000000000000050351263006255200224740ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "signInStatusLabel.h" #include signInStatusLabel::signInStatusLabel(QWidget* parent):QLabel(parent), m_timer(this), m_option(None) { m_timer.setSingleShot(false); bool check = connect(&m_timer, SIGNAL(timeout()), SLOT(timeout())); Q_ASSERT(check); Q_UNUSED(check); } void signInStatusLabel::setCustomText(const QString& text, signInStatusLabel::Option op, int countDown) { m_text = text; m_option = op; m_countDown = countDown; switch(op) { case None: m_timer.stop(); m_postfix = ""; break; case WithProgressEllipsis: // m_timer.start(400); m_postfix = ""; break; case CountDown: m_timer.start(1000); m_postfix = ""; break; default: m_timer.stop(); m_postfix = ""; break; } if(m_option == CountDown) setText(m_text.arg(m_countDown) + m_postfix); else setText(m_text + m_postfix); updateGeometry(); } void signInStatusLabel::timeout() { switch(m_option) { case None: break; case WithProgressEllipsis: if(m_postfix == "") m_postfix = "."; else if(m_postfix == ".") m_postfix = ".."; else if(m_postfix == "..") m_postfix = "..."; else if(m_postfix == "...") m_postfix = ""; break; case CountDown: if(m_countDown == 0) m_timer.stop(); --m_countDown; break; default: break; } if(m_option == CountDown) setText(m_text.arg(m_countDown) + m_postfix); else setText(m_text + m_postfix); updateGeometry(); } //QSize signInStatusLabel::sizeHint() const //{ // QFont font; // QFontMetrics fm(font); // return QSize(fm.width(m_text) + 15, 20); //} qxmpp-0.9.3/examples/GuiClient/signInStatusLabel.h000066400000000000000000000025311263006255200221370ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 SIGNINSTATUSLABEL_H #define SIGNINSTATUSLABEL_H #include #include class signInStatusLabel : public QLabel { Q_OBJECT public: enum Option { None = 0, WithProgressEllipsis, CountDown }; signInStatusLabel(QWidget* parent = 0); void setCustomText(const QString& text, signInStatusLabel::Option op = None, int countDown = 0); // QSize sizeHint() const; private slots: void timeout(); private: QTimer m_timer; signInStatusLabel::Option m_option; QString m_text; QString m_postfix; int m_countDown; }; #endif // SIGNINSTATUSLABEL_H qxmpp-0.9.3/examples/GuiClient/statusAvatarWidget.cpp000066400000000000000000000032431263006255200227260ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "statusAvatarWidget.h" #include statusAvatarWidget::statusAvatarWidget(QWidget* parent) : QPushButton(parent) { } void statusAvatarWidget::paintEvent(QPaintEvent* event) { Q_UNUSED(event); QPainter painter(this); QRect r = rect(); QPixmap pixmap = icon().pixmap(sizeHint(), QIcon::Normal, QIcon::On); if(pixmap.isNull()) pixmap = QPixmap(":/icons/resource/avatar.png"); QRect pixRect(0, 0, 32, 32); pixRect.moveCenter(r.center()); painter.drawPixmap(pixRect, pixmap); if(underMouse() && !isDown()) { painter.drawRect(pixRect.adjusted(0, 0, -1, -1)); QColor col(Qt::white); col.setAlpha(80); painter.fillRect(pixRect.adjusted(0, 0, -1, -1), col); } if(isDown()) { QColor col(Qt::white); col.setAlpha(50); painter.drawRect(pixRect.adjusted(1, 1, -2, -2)); } } QSize statusAvatarWidget::sizeHint() const { return QSize(32, 32); } qxmpp-0.9.3/examples/GuiClient/statusAvatarWidget.h000066400000000000000000000017501263006255200223740ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 STATUSAVATARWIDGET_H #define STATUSAVATARWIDGET_H #include class statusAvatarWidget : public QPushButton { public: statusAvatarWidget(QWidget* parent = 0); void paintEvent(QPaintEvent* event); QSize sizeHint() const; }; #endif // STATUSAVATARWIDGET_H qxmpp-0.9.3/examples/GuiClient/statusTextWidget.cpp000066400000000000000000000113451263006255200224360ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "statusTextWidget.h" #include #include #include #include QSize statusLineEdit::sizeHint() const { QFont font; QFontMetrics fm(font); int width = fm.width(text()); if(width <= (160 - 8)) return QSize(width+8, 18); else return QSize(160, 18); } void statusLineEditButton::paintEvent(QPaintEvent* event) { Q_UNUSED(event); QPainter painter(this); QStyleOptionButton panel; initStyleOption(&panel); QRect r = style()->subElementRect(QStyle::SE_PushButtonFocusRect, &panel, this); QImage image(":/icons/resource/downArrow.png"); QRect rectDelta(0, 0, 7, 4); rectDelta.moveCenter(r.center()); painter.drawImage(rectDelta, image); } void statusLineEdit::focusInEvent(QFocusEvent* event) { QLineEdit::focusInEvent(event); QLineEdit::selectAll(); } void statusLineEdit::mousePressEvent(QMouseEvent* event) { QLineEdit::mousePressEvent(event); QLineEdit::selectAll(); } statusTextWidget::statusTextWidget(QWidget* parent) : QWidget(parent) , m_statusLineEdit(0) , m_statusButton(0) , m_clearStatusTextHistory("Clear Status Message", this) { bool check; Q_UNUSED(check); m_statusLineEdit = new statusLineEdit(this); QHBoxLayout* layout = new QHBoxLayout; layout->addWidget(m_statusLineEdit); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); m_statusButton = new statusLineEditButton(this); layout->addWidget(m_statusButton); setLayout(layout); check = connect(m_statusButton, SIGNAL(clicked(bool)), SLOT(showMenu())); Q_ASSERT(check); check = connect(m_statusLineEdit, SIGNAL(textChanged(QString)), SLOT(textChanged())); Q_ASSERT(check); check = connect(m_statusLineEdit, SIGNAL(editingFinished()), SLOT(statusTextChanged_helper())); Q_ASSERT(check); check = connect(&m_clearStatusTextHistory, SIGNAL(triggered()), SLOT(clearStatusTextHistory())); Q_ASSERT(check); } void statusTextWidget::showMenu() { QMenu menu(this); int size = m_statusTextActionList.size(); for(int i = 0; i < size; ++i) { menu.addAction(m_statusTextActionList.at(size - 1 - i)); } menu.addSeparator(); menu.addAction(&m_clearStatusTextHistory); m_clearStatusTextHistory.setDisabled(size == 0); menu.exec(m_statusLineEdit->mapToGlobal(QPoint(0, m_statusLineEdit->height()))); } void statusTextWidget::textChanged() { m_statusLineEdit->updateGeometry(); } void statusTextWidget::statusTextChanged_helper() { addStatusTextToList(m_statusLineEdit->text()); emit statusTextChanged(m_statusLineEdit->text()); parentWidget()->setFocus(); } void statusTextWidget::setStatusText(const QString& statusText) { m_statusLineEdit->setText(statusText); } void statusTextWidget::addStatusTextToList(const QString& status) { for(int i = 0; i < m_statusTextActionList.size(); ++i) { if(m_statusTextActionList.at(i)->data().toString() == status) { QAction* action = m_statusTextActionList.takeAt(i); m_statusTextActionList.append(action); return; } } QAction* action = new QAction(status, this); action->setData(status); bool check = connect(action, SIGNAL(triggered()), SLOT(statusTextChanged_menuClick())); Q_ASSERT(check); Q_UNUSED(check); m_statusTextActionList.append(action); } void statusTextWidget::statusTextChanged_menuClick() { QAction* action = qobject_cast(sender()); if(action) { int i = 0; while(i < m_statusTextActionList.size() && action != m_statusTextActionList.at(i)) { ++i; } if(action == m_statusTextActionList.at(i)) { m_statusTextActionList.removeAt(i); m_statusTextActionList.append(action); } m_statusLineEdit->setText(action->data().toString()); emit statusTextChanged(action->data().toString()); } } void statusTextWidget::clearStatusTextHistory() { emit statusTextChanged(""); } qxmpp-0.9.3/examples/GuiClient/statusTextWidget.h000066400000000000000000000064641263006255200221110ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 STATUSTEXTWIDGET_H #define STATUSTEXTWIDGET_H #include #include #include #include #include #include #include class statusLineEditButton : public QPushButton { Q_OBJECT public: statusLineEditButton(QWidget* parent = 0): QPushButton(parent) { setCursor(Qt::PointingHandCursor); } void paintEvent(QPaintEvent* event); QSize sizeHint() const { return QSize(14, 14); } }; class statusLineEdit : public QLineEdit { public: statusLineEdit(QWidget* parent = 0) : QLineEdit(parent) { setAttribute(Qt::WA_Hover, true); setText("Available"); setMinimumSize(QSize(20, 18)); } void focusInEvent(QFocusEvent* event); void mousePressEvent(QMouseEvent* event); void paintEvent(QPaintEvent* event) { if(hasFocus()) { QLineEdit::paintEvent(event); } else { QPainter p(this); QRect r = rect(); QPalette pal = palette(); QStyleOptionFrameV2 panel; initStyleOption(&panel); r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this); r.adjust(-1, -1, 0, 0); r.setLeft(r.left() + 4); p.setPen(Qt::darkGray); p.drawText(r, Qt::AlignVCenter, text()); } if(underMouse() && !hasFocus()) { QPainter p(this); QRect r = rect(); QPalette pal = palette(); QStyleOptionFrameV2 panel; initStyleOption(&panel); r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this); r.adjust(-1, -1, 0, 0); p.setPen(Qt::gray); p.drawRect(r); r.setLeft(r.left() + 4); p.setPen(Qt::darkGray); p.drawText(r, Qt::AlignVCenter, text()); } } QSize sizeHint() const; }; class statusTextWidget : public QWidget { Q_OBJECT public: statusTextWidget(QWidget* parent = 0); void setStatusText(const QString& statusText); public slots: void showMenu(); void textChanged(); private slots: void statusTextChanged_helper(); void statusTextChanged_menuClick(); void clearStatusTextHistory(); signals: void statusTextChanged(const QString&); private: void addStatusTextToList(const QString& status); statusLineEdit* m_statusLineEdit; statusLineEditButton* m_statusButton; QList m_statusTextActionList; QAction m_clearStatusTextHistory; }; #endif // STATUSTEXTWIDGET_H qxmpp-0.9.3/examples/GuiClient/statusToolButton.cpp000066400000000000000000000042051263006255200224540ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "statusToolButton.h" #include #include #include statusToolButton::statusToolButton(QWidget* parent) : QToolButton(parent) { setMinimumSize(QSize(20, 18)); } void statusToolButton::paintEvent(QPaintEvent* event) { Q_UNUSED(event); QPainter painter(this); if(underMouse()) { QStyleOptionToolButton panel; initStyleOption(&panel); style()->drawPrimitive(QStyle::PE_PanelButtonTool, &panel, &painter, this); } QRect r = rect(); QFont font; painter.setFont(font); painter.setPen(Qt::gray); QRect rectSize(0, 0, sizeHint().width(), sizeHint().height()); rectSize.moveCenter(r.center()); r = rectSize; r.adjust(0, 0, -1, -1); painter.setPen(Qt::black); painter.setBrush(Qt::black); r.moveLeft(r.left() + 3); font.setBold(true); painter.setFont(font); painter.drawText(r, Qt::AlignVCenter|Qt::TextSingleLine, text()); QImage image(":/icons/resource/downArrow.png"); QRect rectDelta(0, 0, 7, 4); rectDelta.moveRight(r.right() - 4); rectDelta.moveCenter(QPoint(rectDelta.center().x(), r.center().y())); painter.drawImage(rectDelta, image); } QSize statusToolButton::sizeHint() const { QFont font; font.setBold(true); QFontMetrics fm(font); int width = fm.width(text()); if(width <= (160 - 8 - 9)) return QSize(width+8+9, 18); else return QSize(160, 18); } qxmpp-0.9.3/examples/GuiClient/statusToolButton.h000066400000000000000000000017361263006255200221270ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 STATUSTOOLBUTTON_H #define STATUSTOOLBUTTON_H #include class statusToolButton : public QToolButton { public: statusToolButton(QWidget* parent = 0); void paintEvent(QPaintEvent* event); QSize sizeHint() const; }; #endif // STATUSTOOLBUTTON_H qxmpp-0.9.3/examples/GuiClient/statusWidget.cpp000066400000000000000000000112411263006255200215640ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "statusWidget.h" #include #include #include statusWidget::statusWidget(QWidget* parent) : QWidget(parent) { bool check; Q_UNUSED(check); setupUi(this); QMenu* menu = new QMenu(this); menu->addAction(actionAvailable); menu->addAction(actionBusy); menu->addAction(actionAway); // menu->addAction(actionInvisible); menu->addSeparator(); menu->addAction(actionSign_out); toolButton_userName->setMenu(menu); check = connect(statusTextWidgetObject, SIGNAL(statusTextChanged(QString)), SIGNAL(statusTextChanged(QString))); Q_ASSERT(check); check = connect(actionAvailable, SIGNAL(triggered()), SLOT(presenceMenuTriggered())); Q_ASSERT(check); check = connect(actionBusy, SIGNAL(triggered()), SLOT(presenceMenuTriggered())); Q_ASSERT(check); check = connect(actionAway, SIGNAL(triggered()), SLOT(presenceMenuTriggered())); Q_ASSERT(check); // check = connect(actionInvisible, SIGNAL(triggered()), SLOT(presenceMenuTriggered())); // Q_ASSERT(check); check = connect(actionSign_out, SIGNAL(triggered()), SLOT(presenceMenuTriggered())); Q_ASSERT(check); check = connect(pushButton_avatar, SIGNAL(clicked()), SLOT(avatarSelection())); Q_ASSERT(check); } void statusWidget::setStatusText(const QString& statusText) { statusTextWidgetObject->setStatusText(statusText); } void statusWidget::presenceMenuTriggered() { QString icon = "green"; QAction* action = qobject_cast(sender()); if(action == actionAvailable) { emit presenceTypeChanged(QXmppPresence::Available); icon = "green"; } else if(action == actionBusy) { emit presenceStatusTypeChanged(QXmppPresence::DND); icon = "red"; } else if(action == actionAway) { emit presenceStatusTypeChanged(QXmppPresence::Away); icon = "orange"; } #if 0 else if(action == actionInvisible) { emit presenceStatusTypeChanged(QXmppPresence::Invisible); icon = "gray"; } #endif else if(action == actionSign_out) { emit presenceTypeChanged(QXmppPresence::Unavailable); icon = "gray"; } label->setPixmap(QPixmap(":/icons/resource/"+icon+".png")); } void statusWidget::setPresenceAndStatusType(QXmppPresence::Type presenceType, QXmppPresence::AvailableStatusType statusType) { if(presenceType == QXmppPresence::Available) { QString icon = "green"; switch(statusType) { case QXmppPresence::Online: case QXmppPresence::Chat: icon = "green"; break; case QXmppPresence::Away: case QXmppPresence::XA: icon = "orange"; break; case QXmppPresence::DND: icon = "red"; break; case QXmppPresence::Invisible: icon = "gray"; break; } label->setPixmap(QPixmap(":/icons/resource/"+icon+".png")); } else if(presenceType == QXmppPresence::Unavailable) { label->setPixmap(QPixmap(":/icons/resource/gray.png")); } } void statusWidget::avatarSelection() { QString fileFilters = QString("Images (*.png *.jpeg *.jpg *.gif *.bmp);;All Files (*.*)"); QString file = QFileDialog::getOpenFileName(this, "Select your avatar", QString(), fileFilters); if(file.isEmpty()) return; QImage image; if(image.load(file)) { QImage scaled = image.scaled(QSize(96, 96), Qt::KeepAspectRatio, Qt::SmoothTransformation); emit avatarChanged(scaled); } else QMessageBox::information(this, "Avatar selection", "Invalid image file"); } void statusWidget::setDisplayName(const QString& name) { toolButton_userName->setText(name); } void statusWidget::setAvatar(const QImage& image) { pushButton_avatar->setIcon(QIcon(QPixmap::fromImage(image))); } qxmpp-0.9.3/examples/GuiClient/statusWidget.h000066400000000000000000000031271263006255200212350ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 STATUSWIDGET_H #define STATUSWIDGET_H #include "ui_statusWidget.h" #include "QXmppPresence.h" /// Main Widget for the client's status/status text/avatar management class statusWidget : public QWidget, public Ui::statusWidgetClass { Q_OBJECT public: statusWidget(QWidget* parent = 0); void setDisplayName(const QString& name); void setStatusText(const QString& statusText); void setPresenceAndStatusType(QXmppPresence::Type presenceType, QXmppPresence::AvailableStatusType statusType); void setAvatar(const QImage&); private slots: void presenceMenuTriggered(); void avatarSelection(); signals: void statusTextChanged(const QString&); void presenceTypeChanged(QXmppPresence::Type); void presenceStatusTypeChanged(QXmppPresence::AvailableStatusType); void avatarChanged(const QImage&); }; #endif // STATUSWIDGET_H qxmpp-0.9.3/examples/GuiClient/statusWidget.ui000066400000000000000000000135141263006255200214240ustar00rootroot00000000000000 statusWidgetClass 0 0 251 40 Form 0 4 0 4 0 0 0 :/icons/resource/green.png 0 3 0 toolbutton QToolButton::InstantPopup Qt::ToolButtonTextBesideIcon true Qt::DownArrow Qt::Horizontal 40 10 0 0 0 Qt::Horizontal 40 10 :/icons/resource/avatar.png:/icons/resource/avatar.png 32 32 :/icons/resource/red.png:/icons/resource/red.png Busy :/icons/resource/green.png:/icons/resource/green.png Available :/icons/resource/gray.png:/icons/resource/gray.png Invisible :/icons/resource/gray.png:/icons/resource/gray.png Sign out :/icons/resource/orange.png:/icons/resource/orange.png Away statusAvatarWidget QPushButton
statusAvatarWidget.h
statusTextWidget QWidget
statusTextWidget.h
1
statusToolButton QToolButton
statusToolButton.h
qxmpp-0.9.3/examples/GuiClient/utils.cpp000066400000000000000000000111111263006255200202310ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "utils.h" #include #if QT_VERSION >= 0x050000 #include #else #include #endif int comparisonWeightsPresenceStatusType(QXmppPresence::AvailableStatusType statusType) { switch(statusType) { case QXmppPresence::Online: case QXmppPresence::Chat: return 0; case QXmppPresence::DND: return 1; case QXmppPresence::Away: case QXmppPresence::XA: return 2; case QXmppPresence::Invisible: return 3; default: return 5; } } int comparisonWeightsPresenceType(QXmppPresence::Type type) { switch(type) { case QXmppPresence::Available: return 0; case QXmppPresence::Unavailable: return 1; case QXmppPresence::Error: case QXmppPresence::Subscribe: case QXmppPresence::Subscribed: case QXmppPresence::Unsubscribe: case QXmppPresence::Unsubscribed: case QXmppPresence::Probe: return 3; default: return 5; } } QString presenceToStatusText(const QXmppPresence& presence) { QString statusText = presence.statusText(); if(statusText.isEmpty()) { if(presence.type() == QXmppPresence::Available) { switch(presence.availableStatusType()) { case QXmppPresence::Invisible: statusText = "Offline"; break; case QXmppPresence::Online: case QXmppPresence::Chat: statusText = "Available"; break; case QXmppPresence::Away: case QXmppPresence::XA: statusText = "Idle"; break; case QXmppPresence::DND: statusText = "Busy"; break; } } else statusText = "Offline"; } return statusText; } QString getSettingsDir(const QString& bareJid) { #if QT_VERSION >= 0x050000 QStringList dirList = QStandardPaths::standardLocations(QStandardPaths::DataLocation); QString dir = dirList.size() > 0 ? dirList.at(0) : ""; #else QString dir = QDesktopServices::storageLocation(QDesktopServices::DataLocation); #endif if(bareJid.isEmpty()) return dir + "/"; else return QString(dir + "/%1/").arg(bareJid); } QString getSha1HashAsHex(const QByteArray& image) { if(image.isEmpty()) return ""; else return QString(QCryptographicHash::hash(image, QCryptographicHash::Sha1).toHex()); } QImage getImageFromByteArray(const QByteArray& image) { QBuffer buffer; buffer.setData(image); buffer.open(QIODevice::ReadOnly); QImageReader imageReader(&buffer); return imageReader.read(); } QString getImageType1(const QByteArray& image) { QBuffer buffer; buffer.setData(image); buffer.open(QIODevice::ReadOnly); QString format = QImageReader::imageFormat(&buffer); if(format.toUpper() == "PNG") return "image/png"; else if(format.toUpper() == "MNG") return "video/x-mng"; else if(format.toUpper() == "GIF") return "image/gif"; else if(format.toUpper() == "BMP") return "image/bmp"; else if(format.toUpper() == "XPM") return "image/x-xpm"; else if(format.toUpper() == "SVG") return "image/svg+xml"; else if(format.toUpper() == "JPEG") return "image/jpeg"; return "image/unknown"; } bool isValidBareJid(const QString& bareJid) { QRegExp re("^[^@]+@[^@]+$"); return re.exactMatch(bareJid); } QByteArray calculateXor(const QByteArray& data, const QByteArray& key) { if(key.isEmpty()) return data; QByteArray result; for(int i = 0 , j = 0; i < data.length(); ++i , ++j) { if(j == key.length()) j = 0; result.append(data.at(i) ^ key.at(j)); } return result; } qxmpp-0.9.3/examples/GuiClient/utils.h000066400000000000000000000025771263006255200177160ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 CLIENTUTILS_H #define CLIENTUTILS_H #include "QXmppPresence.h" #include #include #include int comparisonWeightsPresenceStatusType(QXmppPresence::AvailableStatusType); int comparisonWeightsPresenceType(QXmppPresence::Type); QString presenceToStatusText(const QXmppPresence& presence); QString getSettingsDir(const QString& bareJid = ""); QString getSha1HashAsHex(const QByteArray& image); QImage getImageFromByteArray(const QByteArray& image); QString getImageType1(const QByteArray& image); bool isValidBareJid(const QString& bareJid); QByteArray calculateXor(const QByteArray& data, const QByteArray& key); #endif // CLIENTUTILS_H qxmpp-0.9.3/examples/GuiClient/vCardCache.cpp000066400000000000000000000101121263006255200210540ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "vCardCache.h" #include "utils.h" #include "QXmppClient.h" #include "QXmppUtils.h" #include "QXmppVCardManager.h" #include #include #include vCardCache::vCardCache(QXmppClient* client) : QObject(client), m_client(client) { } void vCardCache::vCardReceived(const QXmppVCardIq& vcard) { QString from = vcard.from(); if(from.isEmpty() && m_client) from = m_client->configuration().jidBare(); m_mapBareJidVcard[from] = vcard; saveToFile(from); emit vCardReadyToUse(from); } bool vCardCache::isVCardAvailable(const QString& bareJid) const { return m_mapBareJidVcard.contains(bareJid); } // TODO don't request again, if it is already requested void vCardCache::requestVCard(const QString& bareJid) { if(m_client) m_client->vCardManager().requestVCard(bareJid); } //TODO not a good way to handle QXmppVCardIq& vCardCache::getVCard(const QString& bareJid) { return m_mapBareJidVcard[bareJid]; } void vCardCache::saveToFile(const QString& bareJid) { QDir dir; if(!dir.exists(getSettingsDir(m_client->configuration().jidBare()))) dir.mkpath(getSettingsDir(m_client->configuration().jidBare())); QDir dir2; if(!dir2.exists(getSettingsDir(m_client->configuration().jidBare())+ "vCards/")) dir2.mkpath(getSettingsDir(m_client->configuration().jidBare())+ "vCards/"); if(m_mapBareJidVcard.contains(bareJid)) { QString fileVCard = getSettingsDir(m_client->configuration().jidBare()) + "vCards/" + bareJid + ".xml"; QFile file(fileVCard); if(file.open(QIODevice::ReadWrite)) { QXmlStreamWriter stream(&file); stream.setAutoFormatting(true); stream.setAutoFormattingIndent(2); m_mapBareJidVcard[bareJid].toXml(&stream); file.close(); } } } void vCardCache::loadFromFile() { m_mapBareJidVcard.clear(); QDir dirVCards(getSettingsDir(m_client->configuration().jidBare())+ "vCards/"); if(dirVCards.exists()) { QStringList list = dirVCards.entryList(QStringList("*.xml")); foreach(QString fileName, list) { QFile file(getSettingsDir(m_client->configuration().jidBare())+ "vCards/" + fileName); QString bareJid = fileName; bareJid.chop(4); if(file.open(QIODevice::ReadOnly)) { QDomDocument doc; if(doc.setContent(&file, true)) { QXmppVCardIq vCardIq; vCardIq.parse(doc.documentElement()); m_mapBareJidVcard[bareJid] = vCardIq; QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } } } } } //TODO: this should return scaled image QImage vCardCache::getAvatar(const QString& bareJid) const { if(m_mapBareJidVcard.contains(bareJid)) return getImageFromByteArray(m_mapBareJidVcard[bareJid].photo()); else return QImage(); } QByteArray vCardCache::getPhotoHash(const QString& bareJid) const { if(!m_mapBareJidVcard.contains(bareJid)) return QByteArray(); if(m_mapBareJidVcard[bareJid].photo().isEmpty()) return QByteArray(); else return QCryptographicHash::hash(m_mapBareJidVcard[bareJid].photo(), QCryptographicHash::Sha1); } qxmpp-0.9.3/examples/GuiClient/vCardCache.h000066400000000000000000000027621263006255200205350ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 VCARDCACHE_H #define VCARDCACHE_H #include #include #include "QXmppVCardIq.h" class QImage; class QXmppClient; class vCardCache : public QObject { Q_OBJECT public: vCardCache(QXmppClient* client); bool isVCardAvailable(const QString& bareJid) const; void requestVCard(const QString& bareJid); QXmppVCardIq& getVCard(const QString& bareJid); QImage getAvatar(const QString& bareJid) const; void loadFromFile(); QByteArray getPhotoHash(const QString& bareJid) const; signals: void vCardReadyToUse(const QString& bareJid); public slots: void vCardReceived(const QXmppVCardIq&); private: void saveToFile(const QString& bareJid); QXmppClient* m_client; QMap m_mapBareJidVcard; }; #endif // VCARDCACHE_H qxmpp-0.9.3/examples/GuiClient/xmlConsoleDialog.cpp000066400000000000000000000041161263006255200223430ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "xmlConsoleDialog.h" #include "ui_xmlConsoleDialog.h" #include #include static QString s_colorHexSent("#02aa3f"); static QString s_colorHexReceived("#aa0000"); xmlConsoleDialog::xmlConsoleDialog(QWidget *parent) : QDialog(parent, Qt::Window), ui(new Ui::xmlConsoleDialog) { ui->setupUi(this); setWindowTitle("Debugging Console"); ui->label_legend->setText( QString("

Sent | Received

").arg(s_colorHexSent).arg(s_colorHexReceived)); } xmlConsoleDialog::~xmlConsoleDialog() { delete ui; } void xmlConsoleDialog::message(QXmppLogger::MessageType type, const QString& text) { if(!ui->checkBox_enable->isChecked()) return; QColor color; switch(type) { case QXmppLogger::ReceivedMessage: color = QColor(s_colorHexReceived); break; case QXmppLogger::SentMessage: color = QColor(s_colorHexSent); break; default: return; } QDomDocument doc; // Indent XML string bool isXml = doc.setContent(text); QString formattedText; QTextStream stream(&formattedText); doc.save(stream, 2); ui->textBrowser->setTextColor(color); if(isXml) ui->textBrowser->append(formattedText); else ui->textBrowser->append(text); } qxmpp-0.9.3/examples/GuiClient/xmlConsoleDialog.h000066400000000000000000000021741263006255200220120ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 XMLCONSOLEDIALOG_H #define XMLCONSOLEDIALOG_H #include #include "QXmppLogger.h" namespace Ui { class xmlConsoleDialog; } class xmlConsoleDialog : public QDialog { Q_OBJECT public: explicit xmlConsoleDialog(QWidget *parent = 0); ~xmlConsoleDialog(); public slots: void message(QXmppLogger::MessageType, const QString &); private: Ui::xmlConsoleDialog *ui; }; #endif // XMLCONSOLEDIALOG_H qxmpp-0.9.3/examples/GuiClient/xmlConsoleDialog.ui000066400000000000000000000064341263006255200222030ustar00rootroot00000000000000 xmlConsoleDialog 0 0 569 349 Dialog :/icons/resource/icon.png:/icons/resource/icon.png 6 TextLabel Enable true Qt::Horizontal 40 20 Clear 0 0 Qt::Horizontal QDialogButtonBox::Cancel buttonBox accepted() xmlConsoleDialog accept() 389 289 157 274 buttonBox rejected() xmlConsoleDialog reject() 389 289 286 274 pushButton_clear clicked() textBrowser clear() 257 283 178 202 qxmpp-0.9.3/examples/example_0_connected/000077500000000000000000000000001263006255200204035ustar00rootroot00000000000000qxmpp-0.9.3/examples/example_0_connected/README000066400000000000000000000004441263006255200212650ustar00rootroot00000000000000This example just connects to the xmpp server. And start receiving presences (updates) from the server. After running this example, you can see this user online, if it's added in your roster (friends list). Logging type has been set to stdout. You can see the progress on the command line. qxmpp-0.9.3/examples/example_0_connected/example_0_connected.cpp000066400000000000000000000023011263006255200247770ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppClient.h" #include "QXmppLogger.h" int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QXmppClient client; client.logger()->setLoggingType(QXmppLogger::StdoutLogging); // For jabber // client.connectToServer("username@jabber.org", "passwd"); // For google talk // client.connectToServer("username@gmail.com", "passwd"); client.connectToServer("qxmpp.test1@qxmpp.org", "qxmpp123"); return app.exec(); } qxmpp-0.9.3/examples/example_0_connected/example_0_connected.pro000066400000000000000000000001621263006255200250200ustar00rootroot00000000000000include(../examples.pri) TARGET = example_0_connected SOURCES += example_0_connected.cpp OTHER_FILES += README qxmpp-0.9.3/examples/example_1_echoClient/000077500000000000000000000000001263006255200205175ustar00rootroot00000000000000qxmpp-0.9.3/examples/example_1_echoClient/README000066400000000000000000000003301263006255200213730ustar00rootroot00000000000000This is a very simple bot which echoes the message sent to it. Run this example, send it a message from a friend of this bot. You will recieve the message back. This example shows how to receive and send messages. qxmpp-0.9.3/examples/example_1_echoClient/example_1_echoClient.cpp000066400000000000000000000030071263006255200252330ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppLogger.h" #include "QXmppMessage.h" #include "example_1_echoClient.h" echoClient::echoClient(QObject *parent) : QXmppClient(parent) { bool check = connect(this, SIGNAL(messageReceived(QXmppMessage)), SLOT(messageReceived(QXmppMessage))); Q_ASSERT(check); Q_UNUSED(check); } echoClient::~echoClient() { } void echoClient::messageReceived(const QXmppMessage& message) { QString from = message.from(); QString msg = message.body(); sendPacket(QXmppMessage("", from, "Your message: " + msg)); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); echoClient client; client.logger()->setLoggingType(QXmppLogger::StdoutLogging); client.connectToServer("qxmpp.test1@qxmpp.org", "qxmpp123"); return app.exec(); } qxmpp-0.9.3/examples/example_1_echoClient/example_1_echoClient.h000066400000000000000000000017341263006255200247050ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 ECHOCLIENT_H #define ECHOCLIENT_H #include "QXmppClient.h" class echoClient : public QXmppClient { Q_OBJECT public: echoClient(QObject *parent = 0); ~echoClient(); public slots: void messageReceived(const QXmppMessage&); }; #endif // ECHOCLIENT_H qxmpp-0.9.3/examples/example_1_echoClient/example_1_echoClient.pro000066400000000000000000000002271263006255200252520ustar00rootroot00000000000000include(../examples.pri) TARGET = example_1_echoClient SOURCES += example_1_echoClient.cpp HEADERS += example_1_echoClient.h OTHER_FILES += README qxmpp-0.9.3/examples/example_2_rosterHandling/000077500000000000000000000000001263006255200214265ustar00rootroot00000000000000qxmpp-0.9.3/examples/example_2_rosterHandling/README000066400000000000000000000001061263006255200223030ustar00rootroot00000000000000This example demonstrates how to get the roster and presence updates. qxmpp-0.9.3/examples/example_2_rosterHandling/example_2_rosterHandling.cpp000066400000000000000000000045741263006255200270630ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppMessage.h" #include "QXmppRosterManager.h" #include "example_2_rosterHandling.h" xmppClient::xmppClient(QObject *parent) : QXmppClient(parent) { bool check; Q_UNUSED(check); check = connect(this, SIGNAL(connected()), SLOT(clientConnected())); Q_ASSERT(check); check = connect(&this->rosterManager(), SIGNAL(rosterReceived()), SLOT(rosterReceived())); Q_ASSERT(check); /// Then QXmppRoster::presenceChanged() is emitted whenever presence of someone /// in roster changes check = connect(&this->rosterManager(), SIGNAL(presenceChanged(QString,QString)), SLOT(presenceChanged(QString,QString))); Q_ASSERT(check); } xmppClient::~xmppClient() { } void xmppClient::clientConnected() { qDebug("example_2_rosterHandling:: CONNECTED"); } void xmppClient::rosterReceived() { qDebug("example_2_rosterHandling:: Roster received"); foreach (const QString &bareJid, rosterManager().getRosterBareJids()) { QString name = rosterManager().getRosterEntry(bareJid).name(); if(name.isEmpty()) name = "-"; qDebug("example_2_rosterHandling:: Roster received: %s [%s]", qPrintable(bareJid), qPrintable(name)); } } void xmppClient::presenceChanged(const QString& bareJid, const QString& resource) { qDebug("example_2_rosterHandling:: Presence changed %s/%s", qPrintable(bareJid), qPrintable(resource)); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); xmppClient client; client.connectToServer("qxmpp.test1@qxmpp.org", "qxmpp123"); return app.exec(); } qxmpp-0.9.3/examples/example_2_rosterHandling/example_2_rosterHandling.h000066400000000000000000000020571263006255200265220ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 XMPPCLIENT_H #define XMPPCLIENT_H #include "QXmppClient.h" class xmppClient : public QXmppClient { Q_OBJECT public: xmppClient(QObject *parent = 0); ~xmppClient(); public slots: void clientConnected(); void rosterReceived(); void presenceChanged(const QString& bareJid, const QString& resource); }; #endif // XMPPCLIENT_H qxmpp-0.9.3/examples/example_2_rosterHandling/example_2_rosterHandling.pro000066400000000000000000000002431263006255200270660ustar00rootroot00000000000000include(../examples.pri) TARGET = example_2_rosterHandling SOURCES += example_2_rosterHandling.cpp HEADERS += example_2_rosterHandling.h OTHER_FILES += README qxmpp-0.9.3/examples/example_3_transferHandling/000077500000000000000000000000001263006255200217355ustar00rootroot00000000000000qxmpp-0.9.3/examples/example_3_transferHandling/example_3_transferHandling.cpp000066400000000000000000000112211263006255200276640ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Ian Reinhart Geiser * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppMessage.h" #include "QXmppUtils.h" #include "example_3_transferHandling.h" xmppClient::xmppClient(QObject *parent) : QXmppClient(parent), transferManager(0) { bool check; Q_UNUSED(check); // add transfer manager transferManager = new QXmppTransferManager; transferManager->setProxy("proxy.qxmpp.org"); addExtension(transferManager); // uncomment one of the following if you only want to use a specific transfer method: // // transferManager->setSupportedMethods(QXmppTransferJob::InBandMethod); // transferManager->setSupportedMethods(QXmppTransferJob::SocksMethod); check = connect(this, SIGNAL(presenceReceived(QXmppPresence)), this, SLOT(slotPresenceReceived(QXmppPresence))); Q_ASSERT(check); check = connect(transferManager, SIGNAL(fileReceived(QXmppTransferJob*)), this, SLOT(slotFileReceived(QXmppTransferJob*))); Q_ASSERT(check); } void xmppClient::setRecipient(const QString &recipient) { m_recipient = recipient; } /// A file transfer failed. void xmppClient::slotError(QXmppTransferJob::Error error) { qDebug() << "Transmission failed:" << error; } /// A file transfer request was received. void xmppClient::slotFileReceived(QXmppTransferJob *job) { bool check; Q_UNUSED(check); qDebug() << "Got transfer request from:" << job->jid(); check = connect(job, SIGNAL(error(QXmppTransferJob::Error)), this, SLOT(slotError(QXmppTransferJob::Error))); Q_ASSERT(check); check = connect(job, SIGNAL(finished()), this, SLOT(slotFinished())); Q_ASSERT(check); check = connect(job, SIGNAL(progress(qint64,qint64)), this, SLOT(slotProgress(qint64,qint64))); Q_ASSERT(check); // allocate a buffer to receive the file QBuffer *buffer = new QBuffer(this); buffer->open(QIODevice::WriteOnly); job->accept(buffer); } /// A file transfer finished. void xmppClient::slotFinished() { qDebug() << "Transmission finished"; } /// A presence was received void xmppClient::slotPresenceReceived(const QXmppPresence &presence) { bool check; Q_UNUSED(check); // if we don't have a recipient, or if the presence is not from the recipient, // do nothing if (m_recipient.isEmpty() || QXmppUtils::jidToBareJid(presence.from()) != m_recipient || presence.type() != QXmppPresence::Available) return; // send the file and connect to the job's signals QXmppTransferJob *job = transferManager->sendFile(presence.from(), ":/example_3_transferHandling.cpp", "example source code"); check = connect(job, SIGNAL(error(QXmppTransferJob::Error)), this, SLOT(slotError(QXmppTransferJob::Error))); Q_ASSERT(check); check = connect(job, SIGNAL(finished()), this, SLOT(slotFinished())); Q_ASSERT(check); check = connect(job, SIGNAL(progress(qint64,qint64)), this, SLOT(slotProgress(qint64,qint64))); Q_ASSERT(check); } /// A file transfer has made progress. void xmppClient::slotProgress(qint64 done, qint64 total) { qDebug() << "Transmission progress:" << done << "/" << total; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // we want one argument : "send" or "receive" if (argc != 2 || (strcmp(argv[1], "send") && strcmp(argv[1], "receive"))) { fprintf(stderr, "Usage: %s send|receive\n", argv[0]); return EXIT_FAILURE; } xmppClient client; client.logger()->setLoggingType(QXmppLogger::StdoutLogging); if (!strcmp(argv[1], "send")) { client.setRecipient("qxmpp.test2@qxmpp.org"); client.connectToServer("qxmpp.test1@qxmpp.org", "qxmpp123"); } else { client.connectToServer("qxmpp.test2@qxmpp.org", "qxmpp456"); } return a.exec(); } qxmpp-0.9.3/examples/example_3_transferHandling/example_3_transferHandling.h000066400000000000000000000024741263006255200273430ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Ian Reinhart Geiser * * Source: * https://github.com/qxmpp-project/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 IBBCLIENT_H #define IBBCLIENT_H #include "QXmppClient.h" #include "QXmppTransferManager.h" class QBuffer; class xmppClient : public QXmppClient { Q_OBJECT public: xmppClient(QObject *parent = 0); void setRecipient(const QString &recipient); private slots: void slotError(QXmppTransferJob::Error error); void slotFileReceived(QXmppTransferJob *job); void slotFinished(); void slotPresenceReceived(const QXmppPresence &presence); void slotProgress(qint64 done, qint64 total); private: QString m_recipient; QXmppTransferManager *transferManager; }; #endif // IBBCLIENT_H qxmpp-0.9.3/examples/example_3_transferHandling/example_3_transferHandling.pro000066400000000000000000000002771263006255200277130ustar00rootroot00000000000000include(../examples.pri) TARGET = example_3_transferHandling RESOURCES += example_3_transferHandling.qrc SOURCES += example_3_transferHandling.cpp HEADERS += example_3_transferHandling.h qxmpp-0.9.3/examples/example_3_transferHandling/example_3_transferHandling.qrc000066400000000000000000000001621263006255200276710ustar00rootroot00000000000000 example_3_transferHandling.cpp qxmpp-0.9.3/examples/example_4_callHandling/000077500000000000000000000000001263006255200210255ustar00rootroot00000000000000qxmpp-0.9.3/examples/example_4_callHandling/example_4_callHandling.cpp000066400000000000000000000161411263006255200260520ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Ian Reinhart Geiser * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppCallManager.h" #include "QXmppJingleIq.h" #include "QXmppRtpChannel.h" #include "QXmppUtils.h" #include "example_4_callHandling.h" xmppClient::xmppClient(QObject *parent) : QXmppClient(parent) , m_turnPort(0) , m_turnFinished(false) { bool check; Q_UNUSED(check); // add QXmppCallManager extension callManager = new QXmppCallManager; addExtension(callManager); check = connect(this, SIGNAL(connected()), this, SLOT(slotConnected())); Q_ASSERT(check); check = connect(this, SIGNAL(presenceReceived(QXmppPresence)), this, SLOT(slotPresenceReceived(QXmppPresence))); Q_ASSERT(check); check = connect(callManager, SIGNAL(callReceived(QXmppCall*)), this, SLOT(slotCallReceived(QXmppCall*))); Q_ASSERT(check); check = connect(&m_dns, SIGNAL(finished()), this, SLOT(slotDnsLookupFinished())); Q_ASSERT(check); } void xmppClient::setRecipient(const QString &recipient) { m_recipient = recipient; } /// The audio mode of a call changed. void xmppClient::slotAudioModeChanged(QIODevice::OpenMode mode) { QXmppCall *call = qobject_cast(sender()); Q_ASSERT(call); QXmppRtpAudioChannel *channel = call->audioChannel(); // prepare audio format QAudioFormat format; format.setFrequency(channel->payloadType().clockrate()); format.setChannels(channel->payloadType().channels()); format.setSampleSize(16); format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); format.setSampleType(QAudioFormat::SignedInt); // the size in bytes of the audio buffers to/from sound devices // 160 ms seems to be the minimum to work consistently on Linux/Mac/Windows const int bufferSize = (format.frequency() * format.channels() * (format.sampleSize() / 8) * 160) / 1000; if (mode & QIODevice::ReadOnly) { // initialise audio output QAudioOutput *audioOutput = new QAudioOutput(format, this); audioOutput->setBufferSize(bufferSize); audioOutput->start(channel); } if (mode & QIODevice::WriteOnly) { // initialise audio input QAudioInput *audioInput = new QAudioInput(format, this); audioInput->setBufferSize(bufferSize); audioInput->start(channel); } } /// A call was received. void xmppClient::slotCallReceived(QXmppCall *call) { bool check; Q_UNUSED(check); qDebug() << "Got call from:" << call->jid(); check = connect(call, SIGNAL(stateChanged(QXmppCall::State)), this, SLOT(slotCallStateChanged(QXmppCall::State))); Q_ASSERT(check); check = connect(call, SIGNAL(audioModeChanged(QIODevice::OpenMode)), this, SLOT(slotAudioModeChanged(QIODevice::OpenMode))); Q_ASSERT(check); // accept call call->accept(); } /// A call changed state. void xmppClient::slotCallStateChanged(QXmppCall::State state) { if (state == QXmppCall::ActiveState) qDebug("Call active"); else if (state == QXmppCall::DisconnectingState) qDebug("Call disconnecting"); else if (state == QXmppCall::FinishedState) qDebug("Call finished"); } void xmppClient::slotConnected() { // lookup TURN server const QString domain = configuration().domain(); debug(QString("Looking up TURN server for domain %1").arg(domain)); m_dns.setType(QDnsLookup::SRV); m_dns.setName("_turn._udp." + domain); m_dns.lookup(); } /// The DNS SRV lookup for TURN completed. void xmppClient::slotDnsLookupFinished() { QString serverName; if (m_dns.error() == QDnsLookup::NoError && !m_dns.serviceRecords().isEmpty()) { m_turnPort = m_dns.serviceRecords().first().port(); QHostInfo::lookupHost(m_dns.serviceRecords().first().target(), this, SLOT(slotHostInfoFinished(QHostInfo))); } else { warning("Could not find STUN server for domain " + configuration().domain()); m_turnFinished = true; startCall(); } } void xmppClient::slotHostInfoFinished(const QHostInfo &hostInfo) { if (!hostInfo.addresses().isEmpty()) { info(QString("Found TURN server %1 port %2 for domain %3").arg(hostInfo.addresses().first().toString(), QString::number(m_turnPort), configuration().domain())); callManager->setTurnServer(hostInfo.addresses().first(), m_turnPort); callManager->setTurnUser(configuration().user()); callManager->setTurnPassword(configuration().password()); } m_turnFinished = true; startCall(); } /// A presence was received. void xmppClient::slotPresenceReceived(const QXmppPresence &presence) { // if we don't have a recipient, or if the presence is not from the recipient, // do nothing if (m_recipient.isEmpty() || QXmppUtils::jidToBareJid(presence.from()) != m_recipient || presence.type() != QXmppPresence::Available) return; // start the call and connect to the its signals m_recipientFullJid = presence.from(); startCall(); } void xmppClient::startCall() { bool check; Q_UNUSED(check); if (!m_turnFinished || m_recipientFullJid.isEmpty()) return; // start the call and connect to the its signals QXmppCall *call = callManager->call(m_recipientFullJid); check = connect(call, SIGNAL(stateChanged(QXmppCall::State)), this, SLOT(slotCallStateChanged(QXmppCall::State))); Q_ASSERT(check); check = connect(call, SIGNAL(audioModeChanged(QIODevice::OpenMode)), this, SLOT(slotAudioModeChanged(QIODevice::OpenMode))); Q_ASSERT(check); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // we want one argument : "send" or "receive" if (argc != 2 || (strcmp(argv[1], "send") && strcmp(argv[1], "receive"))) { fprintf(stderr, "Usage: %s send|receive\n", argv[0]); return EXIT_FAILURE; } xmppClient client; client.logger()->setLoggingType(QXmppLogger::StdoutLogging); if (!strcmp(argv[1], "send")) { client.setRecipient("qxmpp.test2@qxmpp.org"); client.connectToServer("qxmpp.test1@qxmpp.org", "qxmpp123"); } else { client.connectToServer("qxmpp.test2@qxmpp.org", "qxmpp456"); } return a.exec(); } qxmpp-0.9.3/examples/example_4_callHandling/example_4_callHandling.h000066400000000000000000000030541263006255200255160ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Ian Reinhart Geiser * * Source: * https://github.com/qxmpp-project/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 XMPPCLIENT_H #define XMPPCLIENT_H #include "QXmppCallManager.h" #include "QXmppClient.h" #include "qdnslookup.h" class QHostInfo; class xmppClient : public QXmppClient { Q_OBJECT public: xmppClient(QObject *parent = 0); void setRecipient(const QString &recipient); private slots: void slotAudioModeChanged(QIODevice::OpenMode mode); void slotCallReceived(QXmppCall *call); void slotCallStateChanged(QXmppCall::State state); void slotConnected(); void slotDnsLookupFinished(); void slotHostInfoFinished(const QHostInfo &hostInfo); void slotPresenceReceived(const QXmppPresence &presence); private: void startCall(); QXmppCallManager *callManager; QDnsLookup m_dns; QString m_recipient; QString m_recipientFullJid; quint16 m_turnPort; bool m_turnFinished; }; #endif // IBBCLIENT_H qxmpp-0.9.3/examples/example_4_callHandling/example_4_callHandling.pro000066400000000000000000000004021263006255200260610ustar00rootroot00000000000000include(../examples.pri) CONFIG += mobility MOBILITY += multimedia TARGET = example_4_callHandling SOURCES += example_4_callHandling.cpp HEADERS += example_4_callHandling.h # Symbian packaging rules symbian { TARGET.CAPABILITY = "UserEnvironment" } qxmpp-0.9.3/examples/example_5_rpcInterface/000077500000000000000000000000001263006255200210535ustar00rootroot00000000000000qxmpp-0.9.3/examples/example_5_rpcInterface/example_5_rpcInterface.pro000066400000000000000000000002451263006255200261420ustar00rootroot00000000000000include(../examples.pri) TARGET = example_5_rpcInterface SOURCES += main.cpp \ remoteinterface.cpp HEADERS += remoteinterface.h OTHER_FILES += README qxmpp-0.9.3/examples/example_5_rpcInterface/main.cpp000066400000000000000000000024611263006255200225060ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppClient.h" #include "QXmppLogger.h" #include "QXmppRpcManager.h" #include "remoteinterface.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QXmppLogger::getLogger()->setLoggingType(QXmppLogger::StdoutLogging); QXmppClient client; // add RPC extension and register interface QXmppRpcManager *manager = new QXmppRpcManager; client.addExtension(manager); manager->addInvokableInterface(new RemoteInterface(&client)); client.connectToServer("qxmpp.test1@qxmpp.org", "qxmpp123"); return a.exec(); } qxmpp-0.9.3/examples/example_5_rpcInterface/remoteinterface.cpp000066400000000000000000000004651263006255200247400ustar00rootroot00000000000000#include "remoteinterface.h" RemoteInterface::RemoteInterface(QObject *parent) : QXmppInvokable(parent) { } bool RemoteInterface::isAuthorized( const QString &jid ) const { Q_UNUSED(jid); return true; } QString RemoteInterface::echoString(const QString& message) { return "Echo: " + message; } qxmpp-0.9.3/examples/example_5_rpcInterface/remoteinterface.h000066400000000000000000000005511263006255200244010ustar00rootroot00000000000000#ifndef REMOTEINTERFACE_H #define REMOTEINTERFACE_H #include "QXmppRpcManager.h" class RemoteInterface : public QXmppInvokable { Q_OBJECT public: RemoteInterface(QObject *parent = 0); bool isAuthorized( const QString &jid ) const; // RPC Interface public slots: QString echoString( const QString &message ); }; #endif // REMOTEINTERFACE_H qxmpp-0.9.3/examples/example_5_rpcInterface/xmlrpctest.txt000066400000000000000000000025561263006255200240310ustar00rootroot00000000000000 client telnet Passw0rd RemoteInterface.echoString Test string RemoteInterface.badMethod Test string BadInterface.echoString Test string qxmpp-0.9.3/examples/example_6_rpcClient/000077500000000000000000000000001263006255200203725ustar00rootroot00000000000000qxmpp-0.9.3/examples/example_6_rpcClient/example_6_rpcClient.pro000066400000000000000000000002301263006255200247720ustar00rootroot00000000000000include(../examples.pri) TARGET = example_6_rpcClient SOURCES += main.cpp \ rpcClient.cpp HEADERS += rpcClient.h OTHER_FILES += README qxmpp-0.9.3/examples/example_6_rpcClient/main.cpp000066400000000000000000000020421263006255200220200ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Ian Reinhart Geiser * * Source: * https://github.com/qxmpp-project/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 "rpcClient.h" #include "QXmppLogger.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QXmppLogger::getLogger()->setLoggingType(QXmppLogger::StdoutLogging); rpcClient client; client.connectToServer("qxmpp.test2@qxmpp.org", "qxmpp456"); return a.exec(); } qxmpp-0.9.3/examples/example_6_rpcClient/rpcClient.cpp000066400000000000000000000043141263006255200230230ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Ian Reinhart Geiser * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppRpcManager.h" #include "QXmppUtils.h" #include "rpcClient.h" rpcClient::rpcClient(QObject *parent) : QXmppClient(parent) { // add RPC manager m_rpcManager = new QXmppRpcManager; addExtension(m_rpcManager); // observe incoming presences bool check = connect(this, SIGNAL(presenceReceived(QXmppPresence)), this, SLOT(slotPresenceReceived(QXmppPresence))); Q_ASSERT(check); Q_UNUSED(check); } rpcClient::~rpcClient() { } void rpcClient::slotInvokeRemoteMethod() { QXmppRemoteMethodResult methodResult = m_rpcManager->callRemoteMethod( m_remoteJid, "RemoteInterface.echoString", "This is a test" ); if( methodResult.hasError ) qDebug() << "Error:" << methodResult.code << methodResult.errorMessage; else qDebug() << "Result:" << methodResult.result; } /// A presence was received. void rpcClient::slotPresenceReceived(const QXmppPresence &presence) { const QLatin1String recipient("qxmpp.test1@qxmpp.org"); // if we are the recipient, or if the presence is not from the recipient, // do nothing if (QXmppUtils::jidToBareJid(configuration().jid()) == recipient || QXmppUtils::jidToBareJid(presence.from()) != recipient || presence.type() != QXmppPresence::Available) return; // invoke the remote method in 1 second m_remoteJid = presence.from(); QTimer::singleShot(1000, this, SLOT(slotInvokeRemoteMethod())); } qxmpp-0.9.3/examples/example_6_rpcClient/rpcClient.h000066400000000000000000000021761263006255200224740ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Ian Reinhart Geiser * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 RPCCLIENT_H #define RPCCLIENT_H #include "QXmppClient.h" class QXmppRpcManager; class rpcClient : public QXmppClient { Q_OBJECT public: rpcClient(QObject *parent = 0); ~rpcClient(); private slots: void slotInvokeRemoteMethod(); void slotPresenceReceived(const QXmppPresence &presence); private: QString m_remoteJid; QXmppRpcManager *m_rpcManager; }; #endif // RPCCLIENT_H qxmpp-0.9.3/examples/example_7_archiveHandling/000077500000000000000000000000001263006255200215365ustar00rootroot00000000000000qxmpp-0.9.3/examples/example_7_archiveHandling/example_7_archiveHandling.cpp000066400000000000000000000114051263006255200272720ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppArchiveIq.h" #include "QXmppArchiveManager.h" #include "example_7_archiveHandling.h" static void logStart(const QString &msg) { qDebug("example_7_archiveHandling : %s", qPrintable(msg)); } static void logEnd(const QString &msg) { qDebug(" => %s", qPrintable(msg)); } xmppClient::xmppClient(QObject *parent) : QXmppClient(parent) , m_collectionCount(-1) , m_pageDirection(PageForwards) , m_pageSize(10) { bool check; Q_UNUSED(check); // add archive manager archiveManager = new QXmppArchiveManager; addExtension(archiveManager); // connect signals check = connect(this, SIGNAL(connected()), this, SLOT(clientConnected())); Q_ASSERT(check); check = connect(archiveManager, SIGNAL(archiveChatReceived(QXmppArchiveChat, QXmppResultSetReply)), SLOT(archiveChatReceived(QXmppArchiveChat, QXmppResultSetReply))); Q_ASSERT(check); check = connect(archiveManager, SIGNAL(archiveListReceived(QList, QXmppResultSetReply)), SLOT(archiveListReceived(QList, QXmppResultSetReply))); Q_ASSERT(check); // set limits m_startDate = QDateTime::currentDateTime().addDays(-21); m_endDate = QDateTime::currentDateTime(); } xmppClient::~xmppClient() { } void xmppClient::setPageDirection(PageDirection direction) { m_pageDirection = direction; } void xmppClient::setPageSize(int size) { m_pageSize = size; } void xmppClient::clientConnected() { logEnd("connected"); // we want 0 results, i.e. only result-set management information (count) logStart("fetching collection count"); QXmppResultSetQuery rsmQuery; rsmQuery.setMax(0); archiveManager->listCollections("", m_startDate, m_endDate, rsmQuery); } void xmppClient::archiveListReceived(const QList &chats, const QXmppResultSetReply &rsmReply) { if (m_collectionCount < 0) { logEnd(QString::number(rsmReply.count()) + " items"); m_collectionCount = rsmReply.count(); // fetch first page logStart("fetching collection first page"); QXmppResultSetQuery rsmQuery; rsmQuery.setMax(m_pageSize); if (m_pageDirection == PageBackwards) rsmQuery.setBefore(""); archiveManager->listCollections("", m_startDate, m_endDate, rsmQuery); } else if (!chats.size()) { logEnd("no items"); } else { logEnd(QString("items %1 to %2 of %3").arg(QString::number(rsmReply.index()), QString::number(rsmReply.index() + chats.size() - 1), QString::number(rsmReply.count()))); foreach (const QXmppArchiveChat &chat, chats) { qDebug("chat start %s", qPrintable(chat.start().toString())); // NOTE: to actually retrieve conversations, uncomment this //archiveManager->retrieveCollection(chat.with(), chat.start()); } if (!rsmReply.isNull()) { // fetch next page QXmppResultSetQuery rsmQuery; rsmQuery.setMax(m_pageSize); if (m_pageDirection == PageBackwards) { logStart("fetching collection previous page"); rsmQuery.setBefore(rsmReply.first()); } else { logStart("fetching collection next page"); rsmQuery.setAfter(rsmReply.last()); } archiveManager->listCollections("", m_startDate, m_endDate, rsmQuery); } } } void xmppClient::archiveChatReceived(const QXmppArchiveChat &chat, const QXmppResultSetReply &rsmReply) { logEnd(QString("chat received, RSM count %1").arg(QString::number(rsmReply.count()))); foreach (const QXmppArchiveMessage &msg, chat.messages()) { qDebug("example_7_archiveHandling : %s", qPrintable(msg.body())); } } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); xmppClient client; client.setPageSize(15); client.setPageDirection(xmppClient::PageBackwards); client.connectToServer("qxmpp.test1@qxmpp.org", "qxmpp123"); return a.exec(); } qxmpp-0.9.3/examples/example_7_archiveHandling/example_7_archiveHandling.h000066400000000000000000000031261263006255200267400ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 XMPPCLIENT_H #define XMPPCLIENT_H #include #include "QXmppClient.h" class QXmppArchiveChat; class QXmppArchiveManager; class QXmppResultSetReply; class xmppClient : public QXmppClient { Q_OBJECT public: enum PageDirection { PageForwards = 0, PageBackwards }; xmppClient(QObject *parent = 0); ~xmppClient(); void setPageDirection(PageDirection direction); void setPageSize(int size); public slots: void clientConnected(); void archiveListReceived(const QList &chats, const QXmppResultSetReply &rsmReply); void archiveChatReceived(const QXmppArchiveChat &chat, const QXmppResultSetReply &rsmReply); private: QXmppArchiveManager *archiveManager; int m_collectionCount; QDateTime m_startDate; QDateTime m_endDate; PageDirection m_pageDirection; int m_pageSize; }; #endif // XMPPCLIENT_H qxmpp-0.9.3/examples/example_7_archiveHandling/example_7_archiveHandling.pro000066400000000000000000000002171263006255200273070ustar00rootroot00000000000000include(../examples.pri) TARGET = example_7_archiveHandling SOURCES += example_7_archiveHandling.cpp HEADERS += example_7_archiveHandling.h qxmpp-0.9.3/examples/example_8_server/000077500000000000000000000000001263006255200177575ustar00rootroot00000000000000qxmpp-0.9.3/examples/example_8_server/example_8_server.pro000066400000000000000000000001121263006255200237430ustar00rootroot00000000000000include(../examples.pri) TARGET = example_8_server SOURCES += main.cpp qxmpp-0.9.3/examples/example_8_server/main.cpp000066400000000000000000000040361263006255200214120ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppLogger.h" #include "QXmppPasswordChecker.h" #include "QXmppServer.h" #define USERNAME "qxmpp.test1" #define PASSWORD "qxmpp123" class passwordChecker : public QXmppPasswordChecker { /// Retrieves the password for the given username. QXmppPasswordReply::Error getPassword(const QXmppPasswordRequest &request, QString &password) { if (request.username() == USERNAME) { password = PASSWORD; return QXmppPasswordReply::NoError; } else { return QXmppPasswordReply::AuthorizationError; } }; /// Returns true as we implemented getPassword(). bool hasGetPassword() const { return true; }; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // we want one argument : the domain to serve if (argc != 2) { fprintf(stderr, "Usage: xmppServer \n"); return EXIT_FAILURE; } const QString domain = QString::fromLocal8Bit(argv[1]); QXmppLogger logger; logger.setLoggingType(QXmppLogger::StdoutLogging); passwordChecker checker; QXmppServer server; server.setDomain(domain); server.setLogger(&logger); server.setPasswordChecker(&checker); server.listenForClients(); server.listenForServers(); return a.exec(); } qxmpp-0.9.3/examples/example_9_vCard/000077500000000000000000000000001263006255200175115ustar00rootroot00000000000000qxmpp-0.9.3/examples/example_9_vCard/README000066400000000000000000000001321263006255200203650ustar00rootroot00000000000000This example demonstrates how to get the vCards and handle Avatars of the roster entities.qxmpp-0.9.3/examples/example_9_vCard/example_9_vCard.cpp000066400000000000000000000063401263006255200232220ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppMessage.h" #include "QXmppRosterManager.h" #include "QXmppVCardIq.h" #include "QXmppVCardManager.h" #include "example_9_vCard.h" xmppClient::xmppClient(QObject *parent) : QXmppClient(parent) { bool check; Q_UNUSED(check); check = connect(this, SIGNAL(connected()), SLOT(clientConnected())); Q_ASSERT(check); check = connect(&this->rosterManager(), SIGNAL(rosterReceived()), SLOT(rosterReceived())); Q_ASSERT(check); } xmppClient::~xmppClient() { } void xmppClient::clientConnected() { std::cout<<"example_9_vCard:: CONNECTED"<vCardManager(), SIGNAL(vCardReceived(QXmppVCardIq)), SLOT(vCardReceived(QXmppVCardIq))); Q_ASSERT(check); Q_UNUSED(check); QStringList list = rosterManager().getRosterBareJids(); for(int i = 0; i < list.size(); ++i) { // request vCard of all the bareJids in roster vCardManager().requestVCard(list.at(i)); } } void xmppClient::vCardReceived(const QXmppVCardIq& vCard) { QString bareJid = vCard.from(); std::cout<<"example_9_vCard:: vCard Received:: " << qPrintable(bareJid) < #include "QXmppArchiveIq.h" #include "QXmppConstants.h" #include "QXmppUtils.h" 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) { } /// \cond void QXmppArchiveChat::parse(const QDomElement &element) { m_with = element.attribute("with"); m_start = QXmppUtils::datetimeFromString(element.attribute("start")); m_subject = element.attribute("subject"); m_thread = element.attribute("thread"); m_version = element.attribute("version").toInt(); QDateTime timeAccu = m_start; QDomElement child = element.firstChildElement(); while (!child.isNull()) { if ((child.tagName() == "from") || (child.tagName() == "to")) { QXmppArchiveMessage message; message.setBody(child.firstChildElement("body").text()); timeAccu = timeAccu.addSecs(child.attribute("secs").toInt()); message.setDate(timeAccu); message.setReceived(child.tagName() == "from"); m_messages << message; } child = child.nextSiblingElement(); } } void QXmppArchiveChat::toXml(QXmlStreamWriter *writer, const QXmppResultSetReply &rsm) const { writer->writeStartElement("chat"); writer->writeAttribute("xmlns", ns_archive); helperToXmlAddAttribute(writer, "with", m_with); if (m_start.isValid()) helperToXmlAddAttribute(writer, "start", QXmppUtils::datetimeToString(m_start)); helperToXmlAddAttribute(writer, "subject", m_subject); helperToXmlAddAttribute(writer, "thread", m_thread); if (m_version) helperToXmlAddAttribute(writer, "version", QString::number(m_version)); QDateTime prevTime = m_start; foreach (const QXmppArchiveMessage &message, m_messages) { writer->writeStartElement(message.isReceived() ? "from" : "to"); helperToXmlAddAttribute(writer, "secs", QString::number(prevTime.secsTo(message.date()))); writer->writeTextElement("body", message.body()); writer->writeEndElement(); prevTime = message.date(); } if (!rsm.isNull()) rsm.toXml(writer); writer->writeEndElement(); } /// \endcond /// 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; } /// Returns the result set management reply. /// /// This is used for paging through messages. QXmppResultSetReply QXmppArchiveChatIq::resultSetReply() const { return m_rsmReply; } /// Sets the result set management reply. /// /// This is used for paging through messages. void QXmppArchiveChatIq::setResultSetReply(const QXmppResultSetReply& rsm) { m_rsmReply = rsm; } /// \cond 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) { QDomElement chatElement = element.firstChildElement("chat"); m_chat.parse(chatElement); m_rsmReply.parse(chatElement); } void QXmppArchiveChatIq::toXmlElementFromChild(QXmlStreamWriter *writer) const { m_chat.toXml(writer, m_rsmReply); } /// \endcond /// Constructs a QXmppArchiveListIq. QXmppArchiveListIq::QXmppArchiveListIq() : QXmppIq(QXmppIq::Get) { } /// 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 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; } /// Returns the result set management query. /// /// This is used for paging through conversations. QXmppResultSetQuery QXmppArchiveListIq::resultSetQuery() const { return m_rsmQuery; } /// Sets the result set management query. /// /// This is used for paging through conversations. void QXmppArchiveListIq::setResultSetQuery(const QXmppResultSetQuery& rsm) { m_rsmQuery = rsm; } /// Returns the result set management reply. /// /// This is used for paging through conversations. QXmppResultSetReply QXmppArchiveListIq::resultSetReply() const { return m_rsmReply; } /// Sets the result set management reply. /// /// This is used for paging through conversations. void QXmppArchiveListIq::setResultSetReply(const QXmppResultSetReply& rsm) { m_rsmReply = rsm; } /// \cond 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 = QXmppUtils::datetimeFromString(listElement.attribute("start")); m_end = QXmppUtils::datetimeFromString(listElement.attribute("end")); m_rsmQuery.parse(listElement); m_rsmReply.parse(listElement); 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", QXmppUtils::datetimeToString(m_start)); if (m_end.isValid()) helperToXmlAddAttribute(writer, "end", QXmppUtils::datetimeToString(m_end)); if (!m_rsmQuery.isNull()) m_rsmQuery.toXml(writer); else if (!m_rsmReply.isNull()) m_rsmReply.toXml(writer); 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(); } /// \endcond /// 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; } /// \cond 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 = QXmppUtils::datetimeFromString(listElement.attribute("start")); m_end = QXmppUtils::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", QXmppUtils::datetimeToString(m_start)); if (m_end.isValid()) helperToXmlAddAttribute(writer, "end", QXmppUtils::datetimeToString(m_end)); writer->writeEndElement(); } /// \endcond QXmppArchiveRetrieveIq::QXmppArchiveRetrieveIq() : QXmppIq(QXmppIq::Get) { } /// 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; } /// Returns the result set management query. /// /// This is used for paging through messages. QXmppResultSetQuery QXmppArchiveRetrieveIq::resultSetQuery() const { return m_rsmQuery; } /// Sets the result set management query. /// /// This is used for paging through messages. void QXmppArchiveRetrieveIq::setResultSetQuery(const QXmppResultSetQuery& rsm) { m_rsmQuery = rsm; } /// \cond 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 = QXmppUtils::datetimeFromString(retrieveElement.attribute("start")); m_rsmQuery.parse(retrieveElement); } void QXmppArchiveRetrieveIq::toXmlElementFromChild(QXmlStreamWriter *writer) const { writer->writeStartElement("retrieve"); writer->writeAttribute("xmlns", ns_archive); helperToXmlAddAttribute(writer, "with", m_with); helperToXmlAddAttribute(writer, "start", QXmppUtils::datetimeToString(m_start)); if (!m_rsmQuery.isNull()) m_rsmQuery.toXml(writer); writer->writeEndElement(); } /// \endcond qxmpp-0.9.3/src/base/QXmppArchiveIq.h000066400000000000000000000137671263006255200174220ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppResultSet.h" #include /// \brief The QXmppArchiveMessage class represents an archived message /// as defined by XEP-0136: Message Archiving. class QXMPP_EXPORT 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 class represents an archived conversation /// as defined by XEP-0136: Message Archiving. class QXMPP_EXPORT 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 QXmppResultSetReply &rsm = QXmppResultSetReply()) 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 QXMPP_EXPORT QXmppArchiveChatIq : public QXmppIq { public: QXmppArchiveChat chat() const; void setChat(const QXmppArchiveChat &chat); QXmppResultSetReply resultSetReply() const; void setResultSetReply(const QXmppResultSetReply &rsm); /// \cond static bool isArchiveChatIq(const QDomElement &element); protected: void parseElementFromChild(const QDomElement &element); void toXmlElementFromChild(QXmlStreamWriter *writer) const; /// \endcond private: QXmppArchiveChat m_chat; QXmppResultSetReply m_rsmReply; }; /// \brief Represents an archive list as defined by XEP-0136: Message Archiving. /// /// \ingroup Stanzas class QXMPP_EXPORT QXmppArchiveListIq : public QXmppIq { public: QXmppArchiveListIq(); QList chats() const; void setChats(const QList &chats); QString with() const; void setWith( const QString &with ); QDateTime start() const; void setStart(const QDateTime &start ); QDateTime end() const; void setEnd(const QDateTime &end ); QXmppResultSetQuery resultSetQuery() const; void setResultSetQuery(const QXmppResultSetQuery &rsm); QXmppResultSetReply resultSetReply() const; void setResultSetReply(const QXmppResultSetReply &rsm); /// \cond static bool isArchiveListIq(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; QList m_chats; QXmppResultSetQuery m_rsmQuery; QXmppResultSetReply m_rsmReply; }; /// \brief Represents an archive remove IQ as defined by XEP-0136: Message Archiving. /// /// \ingroup Stanzas class QXMPP_EXPORT 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); protected: 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 QXMPP_EXPORT QXmppArchiveRetrieveIq : public QXmppIq { public: QXmppArchiveRetrieveIq(); QDateTime start() const; void setStart(const QDateTime &start); QString with() const; void setWith(const QString &with); QXmppResultSetQuery resultSetQuery() const; void setResultSetQuery(const QXmppResultSetQuery &rsm); /// \cond static bool isArchiveRetrieveIq(const QDomElement &element); protected: void parseElementFromChild(const QDomElement &element); void toXmlElementFromChild(QXmlStreamWriter *writer) const; /// \endcond private: QString m_with; QDateTime m_start; QXmppResultSetQuery m_rsmQuery; }; /// \brief Represents an archive preference IQ as defined by XEP-0136: Message Archiving. /// /// \ingroup Stanzas class QXMPP_EXPORT QXmppArchivePrefIq : public QXmppIq { public: /// \cond static bool isArchivePrefIq(const QDomElement &element); protected: void parseElementFromChild(const QDomElement &element); void toXmlElementFromChild(QXmlStreamWriter *writer) const; /// \endcond }; #endif // QXMPPARCHIVEIQ_H qxmpp-0.9.3/src/base/QXmppBindIq.cpp000066400000000000000000000041731263006255200172370ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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; } /// \cond 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppBindIq.h000066400000000000000000000026471263006255200167100ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 3921. /// /// \ingroup Stanzas class QXMPP_EXPORT 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 qxmpp-0.9.3/src/base/QXmppBookmarkSet.cpp000066400000000000000000000126231263006255200203110ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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; } /// \cond 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" || childElement.attribute("autojoin") == "1"); 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppBookmarkSet.h000066400000000000000000000045761263006255200177660ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppStanza.h" /// \brief The QXmppBookmarkConference class represents a bookmark for a conference room, /// as defined by XEP-0048: Bookmarks. /// class QXMPP_EXPORT 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 QXMPP_EXPORT 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 QXMPP_EXPORT 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; /// \endcond private: QList m_conferences; QList m_urls; }; #endif qxmpp-0.9.3/src/base/QXmppByteStreamIq.cpp000066400000000000000000000112721263006255200204400ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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" QString QXmppByteStreamIq::StreamHost::host() const { return m_host; } void QXmppByteStreamIq::StreamHost::setHost(const QString &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; } /// \cond 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(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()); 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppByteStreamIq.h000066400000000000000000000043171263006255200201070ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPP_EXPORT QXmppByteStreamIq : public QXmppIq { public: enum Mode { None = 0, Tcp, Udp }; class QXMPP_EXPORT StreamHost { public: QString jid() const; void setJid(const QString &jid); QString host() const; void setHost(const QString &host); quint16 port() const; void setPort(quint16 port); QString zeroconf() const; void setZeroconf(const QString &zeroconf); private: QString 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 qxmpp-0.9.3/src/base/QXmppCodec.cpp000066400000000000000000001264521263006255200171130ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 #include "QXmppCodec_p.h" #include "QXmppRtpChannel.h" #include "QXmppRtpPacket.h" #include #ifdef QXMPP_USE_SPEEX #include #endif #ifdef QXMPP_USE_OPUS #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. */ // Distance (in frames) between two key frames (video only). #define GOPSIZE 32 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. */ static 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 * */ static 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. */ static 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. */ static 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)); } QXmppCodec::~QXmppCodec() { } QXmppVideoDecoder::~QXmppVideoDecoder() { } QXmppVideoEncoder::~QXmppVideoEncoder() { } 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_OPUS QXmppOpusCodec::QXmppOpusCodec(int clockrate, int channels): sampleRate(clockrate), nChannels(channels) { int error; encoder = opus_encoder_create(clockrate, channels, OPUS_APPLICATION_VOIP, &error); if (encoder || error == OPUS_OK) { // Add some options for error correction. opus_encoder_ctl(encoder, OPUS_SET_INBAND_FEC(1)); opus_encoder_ctl(encoder, OPUS_SET_PACKET_LOSS_PERC(20)); opus_encoder_ctl(encoder, OPUS_SET_DTX(1)); #ifdef OPUS_SET_PREDICTION_DISABLED opus_encoder_ctl(encoder, OPUS_SET_PREDICTION_DISABLED(1)); #endif } else qCritical() << "Opus encoder initialization error:" << opus_strerror(error); // Here, clockrate is synonym of sampleRate. decoder = opus_decoder_create(clockrate, channels, &error); if (!encoder || error != OPUS_OK) qCritical() << "Opus decoder initialization error:" << opus_strerror(error); // Opus only supports fixed frame durations from 2.5ms to 60ms. // // NOTE: https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/group__opus__encoder.html validFrameSize << 2.5e-3 << 5e-3 << 10e-3 << 20e-3 << 40e-3 << 60e-3; // so now, calculate the equivalent number of samples to process in each // frame. // // nSamples = t * sampleRate for (int i = 0; i < validFrameSize.size(); i++) validFrameSize[i] *= clockrate; // Maxmimum number of samples for the audio buffer. nSamples = validFrameSize.last(); } QXmppOpusCodec::~QXmppOpusCodec() { if (encoder) { opus_encoder_destroy(encoder); encoder = NULL; } if (decoder) { opus_decoder_destroy(decoder); decoder = NULL; } } qint64 QXmppOpusCodec::encode(QDataStream &input, QDataStream &output) { // Read an audio frame. QByteArray pcm_buffer(input.device()->bytesAvailable(), 0); int length = input.readRawData(pcm_buffer.data(), pcm_buffer.size()); // and append it to the sample buffer. sampleBuffer.append(pcm_buffer.left(length)); // Get the maximum number of samples to encode. It must be a number // accepted by the Opus encoder int samples = readWindow(sampleBuffer.size()); if (samples < 1) return 0; // The encoded stream is supposed to be smaller than the raw stream, so QByteArray opus_buffer(sampleBuffer.size(), 0); length = opus_encode(encoder, (opus_int16 *) sampleBuffer.constData(), samples, (uchar *) opus_buffer.data(), opus_buffer.size()); if (length < 1) qWarning() << "Opus encoding error:" << opus_strerror(length); else // Write the encoded stream to the output. output.writeRawData(opus_buffer.constData(), length); // Remove the frame from the sample buffer. sampleBuffer.remove(0, samples * nChannels * 2); if (length < 1) return 0; return samples; } qint64 QXmppOpusCodec::decode(QDataStream &input, QDataStream &output) { QByteArray opus_buffer(input.device()->bytesAvailable(), 0); int length = input.readRawData(opus_buffer.data(), opus_buffer.size()); if (length < 1) return 0; // Audio frame is nSamples at maximum, so QByteArray pcm_buffer(nSamples * nChannels * 2, 0); // The last argumment must be 1 to enable FEC, but I don't why it results // in a SIGSEV. int samples = opus_decode(decoder, (uchar *) opus_buffer.constData(), length, (opus_int16 *) pcm_buffer.data(), pcm_buffer.size(), 0); if (samples < 1) { qWarning() << "Opus decoding error:" << opus_strerror(samples); return 0; } // Write the audio frame to the output. output.writeRawData(pcm_buffer.constData(), samples * nChannels * 2); return samples; } int QXmppOpusCodec::readWindow(int bufferSize) { // WARNING: We are expecting 2 bytes signed samples, but this is wrong since // input stream can have a different sample formats. // Get the number of frames in the buffer. int samples = bufferSize / nChannels / 2; // Find an appropiate number of samples to read, according to Opus specs. for (int i = validFrameSize.size() - 1; i >= 0; i--) if (validFrameSize[i] <= samples) return validFrameSize[i]; return 0; } #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").toLatin1()); 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) { // With the VPX_DL_REALTIME option, tries to decode the frame as quick as // possible, if not possible discard it. if (vpx_codec_decode(&codec, (const uint8_t*)buffer.constData(), buffer.size(), NULL, VPX_DL_REALTIME) != 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; vpx_codec_flags_t flags = 0; // Enable FEC if codec support it. if (vpx_codec_get_caps(vpx_codec_vp8_dx()) & VPX_CODEC_CAP_ERROR_CONCEALMENT) flags |= VPX_CODEC_USE_ERROR_CONCEALMENT; if (vpx_codec_dec_init(&d->codec, vpx_codec_vp8_dx(), NULL, flags) != 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; const QByteArray payload = packet.payload(); // vp8 deframing: http://tools.ietf.org/html/draft-westin-payload-vp8-00 QDataStream stream(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 = payload.size() - 1; #ifdef QXMPP_DEBUG_VPX qDebug("Vpx fragment FI: %d, size %d", frag_type, packetLength); #endif QXmppVideoFrame frame; static quint16 sequence = 0; // If the incomming packet sequence is wrong discard all packets until a // complete keyframe arrives. // If a partition of a keyframe is missing, discard it until a next // keyframe. // // NOTE: https://tools.ietf.org/html/draft-ietf-payload-vp8-13#section-4.3 // Sections: 4.3, 4.5, 4.5.1 if (frag_type == NoFragment) { // unfragmented packet if ((payload[1] & 0x1) == 0 // is key frame || packet.sequence() == sequence) { if (d->decodeFrame(payload.mid(1), &frame)) frames << frame; sequence = packet.sequence() + 1; } d->packetBuffer.resize(0); } else { // fragments if (frag_type == StartFragment) { // start fragment if ((payload[1] & 0x1) == 0 // is key frame || packet.sequence() == sequence) { d->packetBuffer = payload.mid(1); sequence = packet.sequence() + 1; } } else { // continuation or end fragment if (packet.sequence() == sequence) { 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); } } sequence++; } } } return frames; } bool QXmppVpxDecoder::setParameters(const QMap ¶meters) { Q_UNUSED(parameters); 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(uint clockrate) { d = new QXmppVpxEncoderPrivate; d->frameCount = 0; d->imageBuffer = 0; vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &d->cfg, 0); // Set the encoding threads number to use int nThreads = QThread::idealThreadCount(); if (nThreads > 0) d->cfg.g_threads = nThreads - 1; // Make stream error resiliant d->cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS; d->cfg.g_pass = VPX_RC_ONE_PASS; d->cfg.kf_mode = VPX_KF_AUTO; // Reduce GOP size if (d->cfg.kf_max_dist > GOPSIZE) d->cfg.kf_max_dist = GOPSIZE; // Here, clockrate is synonym of bitrate. d->cfg.rc_target_bitrate = clockrate / 1000; } 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.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 qxmpp-0.9.3/src/base/QXmppCodec_p.h000066400000000000000000000137021263006255200170700ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 #include "QXmppGlobal.h" 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 QXMPP_AUTOTEST_EXPORT QXmppCodec { public: virtual ~QXmppCodec(); /// 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 QXMPP_AUTOTEST_EXPORT 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 #ifdef QXMPP_USE_OPUS typedef struct OpusEncoder OpusEncoder; typedef struct OpusDecoder OpusDecoder; /// \internal /// /// The QXmppOpusCodec class represent a Opus codec. class QXMPP_AUTOTEST_EXPORT QXmppOpusCodec : public QXmppCodec { public: QXmppOpusCodec(int clockrate, int channels); ~QXmppOpusCodec(); qint64 encode(QDataStream &input, QDataStream &output); qint64 decode(QDataStream &input, QDataStream &output); private: OpusEncoder *encoder; OpusDecoder *decoder; int sampleRate; int nChannels; QList validFrameSize; int nSamples; QByteArray sampleBuffer; int readWindow(int bufferSize); }; #endif /// \brief The QXmppVideoDecoder class is the base class for video decoders. /// class QXMPP_AUTOTEST_EXPORT QXmppVideoDecoder { public: virtual ~QXmppVideoDecoder(); /// Returns the format of the video stream. virtual QXmppVideoFormat format() const = 0; /// Handles an RTP \a packet and returns a list of decoded video frames. virtual QList handlePacket(const QXmppRtpPacket &packet) = 0; /// Sets the video stream's \a parameters. virtual bool setParameters(const QMap ¶meters) = 0; }; /// \brief The QXmppVideoEncoder class is the base class for video encoders. /// class QXMPP_AUTOTEST_EXPORT QXmppVideoEncoder { public: virtual ~QXmppVideoEncoder(); /// Sets the \a format of the video stream. virtual bool setFormat(const QXmppVideoFormat &format) = 0; /// Handles a video \a frame and returns a list of RTP packet payloads. virtual QList handleFrame(const QXmppVideoFrame &frame) = 0; /// Returns the video stream's parameters. virtual QMap parameters() const = 0; }; #ifdef QXMPP_USE_THEORA class QXmppTheoraDecoderPrivate; class QXmppTheoraEncoderPrivate; class QXMPP_AUTOTEST_EXPORT QXmppTheoraDecoder : public QXmppVideoDecoder { public: QXmppTheoraDecoder(); ~QXmppTheoraDecoder(); QXmppVideoFormat format() const; QList handlePacket(const QXmppRtpPacket &packet); bool setParameters(const QMap ¶meters); private: QXmppTheoraDecoderPrivate *d; }; class QXMPP_AUTOTEST_EXPORT 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 QXMPP_AUTOTEST_EXPORT QXmppVpxDecoder : public QXmppVideoDecoder { public: QXmppVpxDecoder(); ~QXmppVpxDecoder(); QXmppVideoFormat format() const; QList handlePacket(const QXmppRtpPacket &packet); bool setParameters(const QMap ¶meters); private: QXmppVpxDecoderPrivate *d; }; class QXMPP_AUTOTEST_EXPORT QXmppVpxEncoder : public QXmppVideoEncoder { public: QXmppVpxEncoder(uint clockrate=0); ~QXmppVpxEncoder(); bool setFormat(const QXmppVideoFormat &format); QList handleFrame(const QXmppVideoFrame &frame); QMap parameters() const; private: QXmppVpxEncoderPrivate *d; }; #endif #endif qxmpp-0.9.3/src/base/QXmppConstants.cpp000066400000000000000000000117441263006255200200470ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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_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"; // XEP-0009: Jabber-RPC const char* ns_rpc = "jabber:iq:rpc"; // XEP-0020: Feature Negotiation const char* ns_feature_negotiation = "http://jabber.org/protocol/feature-neg"; // XEP-0030: Service Discovery const char* ns_disco_info = "http://jabber.org/protocol/disco#info"; const char* ns_disco_items = "http://jabber.org/protocol/disco#items"; // XEP-0033: Extended Stanza Addressing const char* ns_extended_addressing = "http://jabber.org/protocol/address"; // XEP-0045: Multi-User Chat 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"; // XEP-0047: In-Band Bytestreams const char* ns_ibb = "http://jabber.org/protocol/ibb"; // XEP-0049: Private XML Storage const char* ns_private = "jabber:iq:private"; // XEP-0054: vcard-temp const char* ns_vcard = "vcard-temp"; // XEP-0059: Result Set Management const char* ns_rsm = "http://jabber.org/protocol/rsm"; // XEP-0065: SOCKS5 Bytestreams const char* ns_bytestreams = "http://jabber.org/protocol/bytestreams"; // XEP-0071: XHTML-IM const char *ns_xhtml_im = "http://jabber.org/protocol/xhtml-im"; // XEP-0077: In-Band Registration const char* ns_register = "jabber:iq:register"; // XEP-0078: Non-SASL Authentication const char* ns_auth = "jabber:iq:auth"; const char* ns_authFeature = "http://jabber.org/features/iq-auth"; // XEP-0085: Chat State Notifications const char* ns_chat_states = "http://jabber.org/protocol/chatstates"; // XEP-0091: Legacy Delayed Delivery const char* ns_legacy_delayed_delivery = "jabber:x:delay"; // XEP-0092: Software Version const char* ns_version = "jabber:iq:version"; const char* ns_data = "jabber:x:data"; // XEP-0095: Stream Initiation 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"; // XEP-0108: User Activity const char* ns_activity = "http://jabber.org/protocol/activity"; // XEP-0115: Entity Capabilities const char* ns_capabilities = "http://jabber.org/protocol/caps"; // XEP-0136: Message Archiving const char* ns_archive = "urn:xmpp:archive"; // XEP-0138: Stream Compression const char* ns_compress = "http://jabber.org/protocol/compress"; const char* ns_compressFeature = "http://jabber.org/features/compress"; // XEP-0145: Annotations const char* ns_rosternotes = "storage:rosternotes"; // XEP-0153: vCard-Based Avatars const char* ns_vcard_update = "vcard-temp:x:update"; // XEP-0158: CAPTCHA Forms const char* ns_captcha = "urn:xmpp:captcha"; // 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-0184: Message Receipts const char* ns_message_receipts = "urn:xmpp:receipts"; // XEP-0199: XMPP Ping const char* ns_ping = "urn:xmpp:ping"; // XEP-0202: Entity Time const char* ns_entity_time = "urn:xmpp:time"; // XEP-0203: Delayed Delivery const char* ns_delayed_delivery = "urn:xmpp:delay"; // XEP-0220: Server Dialback const char* ns_server_dialback = "jabber:server:dialback"; // XEP-0221: Data Forms Media Element const char* ns_media_element = "urn:xmpp:media-element"; // XEP-0224: Attention const char* ns_attention = "urn:xmpp:attention:0"; // XEP-0231: Bits of Binary const char* ns_bob = "urn:xmpp:bob"; // XEP-0249: Direct MUC Invitations const char* ns_conference = "jabber:x:conference"; // XEP-0333: Chat Markers const char* ns_chat_markers = "urn:xmpp:chat-markers:0"; qxmpp-0.9.3/src/base/QXmppConstants.h000066400000000000000000000073011263006255200175060ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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_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; // XEP-0009: Jabber-RPC extern const char* ns_rpc; // XEP-0020: Feature Negotiation extern const char* ns_feature_negotiation; // XEP-0030: Service Discovery extern const char* ns_disco_info; extern const char* ns_disco_items; // XEP-0033: Extended Stanza Addressing extern const char* ns_extended_addressing; // XEP-0045: Multi-User Chat extern const char* ns_muc; extern const char* ns_muc_admin; extern const char* ns_muc_owner; extern const char* ns_muc_user; // XEP-0047: In-Band Bytestreams extern const char* ns_ibb; // XEP-0049: Private XML Storage extern const char* ns_private; // XEP-0054: vcard-temp extern const char* ns_vcard; // XEP-0059: Result Set Management extern const char* ns_rsm; // XEP-0065: SOCKS5 Bytestreams extern const char* ns_bytestreams; // XEP-0071: XHTML-IM extern const char *ns_xhtml_im; // XEP-0077: In-Band Registration extern const char* ns_register; // XEP-0078: Non-SASL Authentication extern const char* ns_auth; extern const char* ns_authFeature; // XEP-0085: Chat State Notifications extern const char* ns_chat_states; // XEP-0091: Legacy Delayed Delivery extern const char* ns_legacy_delayed_delivery; // XEP-0092: Software Version extern const char* ns_version; extern const char* ns_data; // XEP-0095: Stream Initiation extern const char* ns_stream_initiation; extern const char* ns_stream_initiation_file_transfer; // XEP-0108: User Activity extern const char* ns_activity; // XEP-0115: Entity Capabilities extern const char* ns_capabilities; // XEP-0136: Message Archiving extern const char* ns_archive; // XEP-0138: Stream Compression extern const char* ns_compress; extern const char* ns_compressFeature; // XEP-0145: Annotations extern const char* ns_rosternotes; // XEP-0153: vCard-Based Avatars extern const char* ns_vcard_update; // XEP-0158: CAPTCHA Forms extern const char* ns_captcha; // XEP-0166: Jingle 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; // XEP-0184: Message Receipts extern const char* ns_message_receipts; // XEP-0199: XMPP Ping extern const char* ns_ping; // XEP-0202: Entity Time extern const char* ns_entity_time; // XEP-0203: Delayed Delivery extern const char* ns_delayed_delivery; // XEP-0220: Server Dialback extern const char* ns_server_dialback; // XEP-0221: Data Forms Media Element extern const char* ns_media_element; // XEP-0224: Attention extern const char* ns_attention; // XEP-0231: Bits of Binary extern const char* ns_bob; // XEP-0249: Direct MUC Invitations extern const char* ns_conference; // XEP-0333: Char Markers extern const char* ns_chat_markers; #endif // QXMPPCONSTANTS_H qxmpp-0.9.3/src/base/QXmppDataForm.cpp000066400000000000000000000372241263006255200175710ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "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}, }; class QXmppDataFormMediaPrivate : public QSharedData { public: QSize size; QList > uris; }; /// Constructs an empty QXmppDataForm::Media. QXmppDataForm::Media::Media() : d(new QXmppDataFormMediaPrivate) { } /// Constructs a copy of \a other. QXmppDataForm::Media::Media(const QXmppDataForm::Media &other) : d(other.d) { } /// Destroys the media. QXmppDataForm::Media::~Media() { } /// Assigns \a other to this media. QXmppDataForm::Media& QXmppDataForm::Media::operator=(const QXmppDataForm::Media &other) { d = other.d; return *this; } /// Returns media's height. int QXmppDataForm::Media::height() const { return d->size.height(); } /// Sets media's \a height. void QXmppDataForm::Media::setHeight(int height) { d->size.setHeight(height); } /// Returns media's width. int QXmppDataForm::Media::width() const { return d->size.width(); } /// Sets media's \a width. void QXmppDataForm::Media::setWidth(int width) { d->size.setWidth(width); } /// Returns media's uris. QList< QPair< QString, QString > > QXmppDataForm::Media::uris() const { return d->uris; } /// Sets media's \a uris. void QXmppDataForm::Media::setUris(const QList< QPair< QString, QString > > &uris) { d->uris = uris; } /// Returns true if no media tag present. bool QXmppDataForm::Media::isNull() const { return d->uris.empty(); } class QXmppDataFormFieldPrivate : public QSharedData { public: QXmppDataFormFieldPrivate(); QString description; QString key; QString label; QXmppDataForm::Media media; QList > options; bool required; QXmppDataForm::Field::Type type; QVariant value; }; QXmppDataFormFieldPrivate::QXmppDataFormFieldPrivate() : required(false) , type(QXmppDataForm::Field::TextSingleField) { } /// Constructs a QXmppDataForm::Field of the specified \a type. QXmppDataForm::Field::Field(QXmppDataForm::Field::Type type) : d(new QXmppDataFormFieldPrivate) { d->type = type; } /// Constructs a copy of \a other. QXmppDataForm::Field::Field(const QXmppDataForm::Field &other) : d(other.d) { } /// Destroys the form field. QXmppDataForm::Field::~Field() { } /// Assigns \a other to this field. QXmppDataForm::Field& QXmppDataForm::Field::operator=(const QXmppDataForm::Field &other) { d = other.d; return *this; } /// Returns the field's description. QString QXmppDataForm::Field::description() const { return d->description; } /// Sets the field's description. /// /// \param description void QXmppDataForm::Field::setDescription(const QString &description) { d->description = description; } /// Returns the field's key. QString QXmppDataForm::Field::key() const { return d->key; } /// Sets the field's key. /// /// \param key void QXmppDataForm::Field::setKey(const QString &key) { d->key = key; } /// Returns the field's label. QString QXmppDataForm::Field::label() const { return d->label; } /// Sets the field's label. /// /// \param label void QXmppDataForm::Field::setLabel(const QString &label) { d->label = label; } /// Returns the field's media. QXmppDataForm::Media QXmppDataForm::Field::media() const { return d->media; } /// Sets the field's \a media. void QXmppDataForm::Field::setMedia(const QXmppDataForm::Media &media) { d->media = media; } /// Returns the field's options. QList > QXmppDataForm::Field::options() const { return d->options; } /// Sets the field's options. /// /// \param options void QXmppDataForm::Field::setOptions(const QList > &options) { d->options = options; } /// Returns true if the field is required, false otherwise. bool QXmppDataForm::Field::isRequired() const { return d->required; } /// Set to true if the field is required, false otherwise. /// /// \param required void QXmppDataForm::Field::setRequired(bool required) { d->required = required; } /// Returns the field's type. QXmppDataForm::Field::Type QXmppDataForm::Field::type() const { return d->type; } /// Sets the field's type. /// /// \param type void QXmppDataForm::Field::setType(QXmppDataForm::Field::Type type) { d->type = type; } /// Returns the field's value. QVariant QXmppDataForm::Field::value() const { return d->value; } /// Sets the field's value. /// /// \param value void QXmppDataForm::Field::setValue(const QVariant &value) { d->value = value; } class QXmppDataFormPrivate : public QSharedData { public: QXmppDataFormPrivate(); QString instructions; QList fields; QString title; QXmppDataForm::Type type; }; QXmppDataFormPrivate::QXmppDataFormPrivate() : type(QXmppDataForm::None) { } /// Constructs a QXmppDataForm of the specified \a type. QXmppDataForm::QXmppDataForm(QXmppDataForm::Type type) : d(new QXmppDataFormPrivate) { d->type = type; } /// Constructs a copy of \a other. QXmppDataForm::QXmppDataForm(const QXmppDataForm &other) : d(other.d) { } /// Destroys the form. QXmppDataForm::~QXmppDataForm() { } /// Assigns \a other to this form. QXmppDataForm& QXmppDataForm::operator=(const QXmppDataForm &other) { d = other.d; return *this; } /// Returns the form's fields. QList QXmppDataForm::fields() const { return d->fields; } /// Returns the form's fields by reference. QList &QXmppDataForm::fields() { return d->fields; } /// Sets the form's fields. /// /// \param fields void QXmppDataForm::setFields(const QList &fields) { d->fields = fields; } /// Returns the form's instructions. QString QXmppDataForm::instructions() const { return d->instructions; } /// Sets the form's instructions. /// /// \param instructions void QXmppDataForm::setInstructions(const QString &instructions) { d->instructions = instructions; } /// Returns the form's title. QString QXmppDataForm::title() const { return d->title; } /// Sets the form's title. /// /// \param title void QXmppDataForm::setTitle(const QString &title) { d->title = title; } /// Returns the form's type. QXmppDataForm::Type QXmppDataForm::type() const { return d->type; } /// Sets the form's type. /// /// \param type void QXmppDataForm::setType(QXmppDataForm::Type type) { d->type = type; } /// Returns true if the form has an unknown type. bool QXmppDataForm::isNull() const { return d->type == QXmppDataForm::None; } /// \cond void QXmppDataForm::parse(const QDomElement &element) { if (element.isNull()) return; /* form type */ const QString typeStr = element.attribute("type"); if (typeStr == "form") d->type = QXmppDataForm::Form; else if (typeStr == "submit") d->type = QXmppDataForm::Submit; else if (typeStr == "cancel") d->type = QXmppDataForm::Cancel; else if (typeStr == "result") d->type = QXmppDataForm::Result; else { qWarning() << "Unknown form type" << typeStr; return; } /* form properties */ d->title = element.firstChildElement("title").text(); d->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 media */ QDomElement mediaElement = fieldElement.firstChildElement("media"); if (!mediaElement.isNull()) { Media media; media.setHeight(mediaElement.attribute("height", "-1").toInt()); media.setWidth(mediaElement.attribute("width", "-1").toInt()); QList > uris; QDomElement uriElement = mediaElement.firstChildElement("uri"); while (!uriElement.isNull()) { uris.append(QPair(uriElement.attribute("type"), uriElement.text())); uriElement = uriElement.nextSiblingElement("uri"); } media.setUris(uris); field.setMedia(media); } /* 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()); d->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 (d->type == QXmppDataForm::Form) typeStr = "form"; else if (d->type == QXmppDataForm::Submit) typeStr = "submit"; else if (d->type == QXmppDataForm::Cancel) typeStr = "cancel"; else if (d->type == QXmppDataForm::Result) typeStr = "result"; writer->writeAttribute("type", typeStr); /* form properties */ if (!d->title.isEmpty()) writer->writeTextElement("title", d->title); if (!d->instructions.isEmpty()) writer->writeTextElement("instructions", d->instructions); foreach (const QXmppDataForm::Field &field, d->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; } } writer->writeAttribute("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 if (!field.value().isNull()) { helperToXmlAddTextElement(writer, "value", field.value().toString()); } /* field media */ Media media = field.media(); if (!media.isNull()) { writer->writeStartElement("media"); helperToXmlAddAttribute(writer, "xmlns", ns_media_element); if (media.height() > 0) helperToXmlAddAttribute(writer, "height", QString::number(media.height())); if (media.width() > 0) helperToXmlAddAttribute(writer, "width", QString::number(media.width())); QPair uri; foreach(uri, media.uris()) { writer->writeStartElement("uri"); helperToXmlAddAttribute(writer, "type", uri.first); writer->writeCharacters(uri.second); writer->writeEndElement(); } writer->writeEndElement(); } /* 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppDataForm.h000066400000000000000000000113131263006255200172250ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppStanza.h" class QXmppDataFormPrivate; class QXmppDataFormFieldPrivate; class QXmppDataFormMediaPrivate; /// \brief The QXmppDataForm class represents a data form as defined by /// XEP-0004: Data Forms. /// class QXMPP_EXPORT QXmppDataForm { public: /// \brief The QXmppDataForm::Media class represents a media field /// as defined by XEP-0221: Data Forms Media Element. /// class QXMPP_EXPORT Media { public: Media(); Media(const QXmppDataForm::Media &other); ~Media(); QXmppDataForm::Media& operator=(const QXmppDataForm::Media &other); int height() const; void setHeight(int height); int width() const; void setWidth(int width); QList > uris() const; void setUris(const QList > &uris); bool isNull() const; private: QSharedDataPointer d; }; /// \brief The QXmppDataForm::Field class represents a data form field /// as defined by XEP-0004: Data Forms. /// class QXMPP_EXPORT 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); Field(const QXmppDataForm::Field &other); ~Field(); QXmppDataForm::Field& operator=(const QXmppDataForm::Field &other); QString description() const; void setDescription(const QString &description); QString key() const; void setKey(const QString &key); QString label() const; void setLabel(const QString &label); Media media() const; void setMedia(const Media &media); 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: QSharedDataPointer d; }; /// 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); QXmppDataForm(const QXmppDataForm &other); ~QXmppDataForm(); QXmppDataForm& operator=(const QXmppDataForm &other); 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: QSharedDataPointer d; }; #endif qxmpp-0.9.3/src/base/QXmppDiscoveryIq.cpp000066400000000000000000000224461263006255200203350ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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); sortedFeatures.removeDuplicates(); 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("<"); if (!m_form.isNull()) { QMap fieldMap; foreach (const QXmppDataForm::Field &field, m_form.fields()) { fieldMap.insert(field.key(), field); } if (fieldMap.contains("FORM_TYPE")) { const QXmppDataForm::Field field = fieldMap.take("FORM_TYPE"); S += field.value().toString() + QLatin1String("<"); QStringList keys = fieldMap.keys(); qSort(keys); foreach (const QString &key, keys) { const QXmppDataForm::Field field = fieldMap.value(key); S += key + QLatin1String("<"); if (field.value().canConvert()) { QStringList list = field.value().toStringList(); list.sort(); S += list.join(QLatin1String("<")); } else { S += field.value().toString(); } S += QLatin1String("<"); } } else { qWarning("QXmppDiscoveryIq form does not contain FORM_TYPE"); } } QCryptographicHash hasher(QCryptographicHash::Sha1); hasher.addData(S.toUtf8()); return hasher.result(); } /// \cond 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")); // FIXME: for some reason the language does not found, // so we are forced to use QDomNamedNodeMap QDomNamedNodeMap m(itemElement.attributes()); for (int i = 0; i < m.size(); ++i) { if (m.item(i).nodeName() == "xml:lang") { identity.setLanguage(m.item(i).nodeValue()); break; } } 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); if (m_queryType == InfoQuery) { 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 QString &feature, m_features) { writer->writeStartElement("feature"); helperToXmlAddAttribute(writer, "var", feature); writer->writeEndElement(); } } else { 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppDiscoveryIq.h000066400000000000000000000054571263006255200200050ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPP_EXPORT QXmppDiscoveryIq : public QXmppIq { public: class QXMPP_EXPORT 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 QXMPP_EXPORT 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 qxmpp-0.9.3/src/base/QXmppElement.cpp000066400000000000000000000134421263006255200174610ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 #include class QXmppElementPrivate { public: QXmppElementPrivate(); QXmppElementPrivate(const QDomElement &element); ~QXmppElementPrivate(); QAtomicInt counter; QXmppElementPrivate *parent; QMap attributes; QList children; QString name; QString value; QByteArray serializedSource; }; 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(); } QTextStream stream(&serializedSource); element.save(stream, 0); } 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; } QDomElement QXmppElement::sourceDomElement() const { if (d->serializedSource.isEmpty()) return QDomElement(); QDomDocument doc; if (!doc.setContent(d->serializedSource, true)) { qWarning("[QXmpp] QXmppElement::sourceDomElement(): cannot parse source element"); return QDomElement(); } return doc.documentElement(); } 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(); } qxmpp-0.9.3/src/base/QXmppElement.h000066400000000000000000000036451263006255200171320ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 #include "QXmppGlobal.h" class QDomElement; class QXmppElement; class QXmppElementPrivate; typedef QList QXmppElementList; class QXMPP_EXPORT QXmppElement { public: QXmppElement(); QXmppElement(const QXmppElement &other); QXmppElement(const QDomElement &element); ~QXmppElement(); QDomElement sourceDomElement() const; 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 qxmpp-0.9.3/src/base/QXmppEntityTimeIq.cpp000066400000000000000000000044031263006255200204520ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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; } /// \cond 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 = QXmppUtils::timezoneOffsetFromString(timeElement.firstChildElement("tzo").text()); m_utc = QXmppUtils::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", QXmppUtils::timezoneOffsetToString(m_tzo)); helperToXmlAddTextElement(writer, "utc", QXmppUtils::datetimeToString(m_utc)); } writer->writeEndElement(); } /// \endcond qxmpp-0.9.3/src/base/QXmppEntityTimeIq.h000066400000000000000000000024521263006255200201210ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 QXMPP_EXPORT 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 qxmpp-0.9.3/src/base/QXmppGlobal.cpp000066400000000000000000000017011263006255200172630ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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)); } qxmpp-0.9.3/src/base/QXmppGlobal.h000066400000000000000000000030111263006255200167240ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 #if defined(QXMPP_STATIC) # define QXMPP_EXPORT #else # if defined(QXMPP_BUILD) # define QXMPP_EXPORT Q_DECL_EXPORT # else # define QXMPP_EXPORT Q_DECL_IMPORT # endif #endif #if defined(QXMPP_AUTOTEST_INTERNAL) # define QXMPP_AUTOTEST_EXPORT QXMPP_EXPORT #else # define QXMPP_AUTOTEST_EXPORT #endif /// 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 0x000903 QXMPP_EXPORT QString QXmppVersion(); #endif //QXMPPGLOBAL_H qxmpp-0.9.3/src/base/QXmppIbbIq.cpp000066400000000000000000000101021263006255200170440ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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; } /// \cond 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(); } /// \endcond QXmppIbbCloseIq::QXmppIbbCloseIq() : QXmppIq(QXmppIq::Set) { } QString QXmppIbbCloseIq::sid() const { return m_sid; } void QXmppIbbCloseIq::setSid( const QString &sid ) { m_sid = sid; } /// \cond 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(); } /// \endcond 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; } /// \cond 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppIbbIq.h000066400000000000000000000043751263006255200165300ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 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 QXMPP_EXPORT 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 qxmpp-0.9.3/src/base/QXmppIq.cpp000066400000000000000000000056731263006255200164500ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 static const char* iq_types[] = { "error", "get", "set", "result" }; class QXmppIqPrivate : public QSharedData { public: QXmppIq::Type type; }; /// Constructs a QXmppIq with the specified \a type. /// /// \param type QXmppIq::QXmppIq(QXmppIq::Type type) : QXmppStanza() , d(new QXmppIqPrivate) { d->type = type; generateAndSetNextId(); } /// Constructs a copy of \a other. QXmppIq::QXmppIq(const QXmppIq &other) : QXmppStanza(other) , d(other.d) { } QXmppIq::~QXmppIq() { } /// Assigns \a other to this IQ. QXmppIq& QXmppIq::operator=(const QXmppIq &other) { QXmppStanza::operator=(other); d = other.d; return *this; } /// Returns the IQ's type. /// QXmppIq::Type QXmppIq::type() const { return d->type; } /// Sets the IQ's type. /// /// \param type void QXmppIq::setType(QXmppIq::Type type) { d->type = type; } /// \cond void QXmppIq::parse(const QDomElement &element) { QXmppStanza::parse(element); const QString type = element.attribute("type"); for (int i = Error; i <= Result; i++) { if (type == iq_types[i]) { d->type = static_cast(i); break; } } 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()); helperToXmlAddAttribute(xmlWriter, "type", iq_types[d->type]); toXmlElementFromChild(xmlWriter); error().toXml(xmlWriter); xmlWriter->writeEndElement(); } void QXmppIq::toXmlElementFromChild( QXmlStreamWriter *writer ) const { foreach (const QXmppElement &extension, extensions()) extension.toXml(writer); } /// \endcond qxmpp-0.9.3/src/base/QXmppIq.h000066400000000000000000000036541263006255200161120ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 class QXmppIqPrivate; /// \brief The QXmppIq class is the base class for all IQs. /// /// \ingroup Stanzas class QXMPP_EXPORT 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(const QXmppIq &other); ~QXmppIq(); QXmppIq& operator=(const QXmppIq &other); 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: QSharedDataPointer d; }; #endif // QXMPPIQ_H qxmpp-0.9.3/src/base/QXmppJingleIq.cpp000066400000000000000000001120331263006255200175660ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppConstants.h" #include "QXmppJingleIq.h" #include "QXmppUtils.h" static const int RTP_COMPONENT = 1; static const char* ns_jingle_rtp_info = "urn:xmpp:jingle:apps:rtp:info:1"; static const char* ns_jingle_dtls = "urn:xmpp:jingle:apps:dtls:0"; 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", }; static QString formatFingerprint(const QByteArray &digest) { QString fingerprint; const QString hx = digest.toHex().toUpper(); for (int i = 0; i < hx.size(); i+=2) { if (!fingerprint.isEmpty()) fingerprint += ':'; fingerprint += hx.mid(i, 2); } return fingerprint; } static QByteArray parseFingerprint(const QString &fingerprint) { QString z = fingerprint; z.replace(':', ""); return QByteArray::fromHex(z.toUtf8()); } static QString addressToSdp(const QHostAddress &host) { return QString("IN %1 %2").arg( host.protocol() == QAbstractSocket::IPv6Protocol ? "IP6" : "IP4", host.toString()); } static bool candidateParseSdp(QXmppJingleCandidate *candidate, const QString &sdp) { if (!sdp.startsWith("candidate:")) return false; const QStringList bits = sdp.mid(10).split(" "); if (bits.size() < 6) return false; candidate->setFoundation(bits[0]); candidate->setComponent(bits[1].toInt()); candidate->setProtocol(bits[2].toLower()); candidate->setPriority(bits[3].toInt()); candidate->setHost(QHostAddress(bits[4])); candidate->setPort(bits[5].toInt()); for (int i = 6; i < bits.size() - 1; i += 2) { if (bits[i] == "typ") { bool ok; candidate->setType(QXmppJingleCandidate::typeFromString(bits[i + 1], &ok)); if (!ok) return false; } else if (bits[i] == "generation") { candidate->setGeneration(bits[i + 1].toInt()); } else { qWarning() << "Candidate SDP contains unknown attribute" << bits[i]; return false; } } return true; } static QString candidateToSdp(const QXmppJingleCandidate &candidate) { return QString("candidate:%1 %2 %3 %4 %5 %6 typ %7 generation %8").arg( candidate.foundation(), QString::number(candidate.component()), candidate.protocol(), QString::number(candidate.priority()), candidate.host().toString(), QString::number(candidate.port()), QXmppJingleCandidate::typeToString(candidate.type()), QString::number(candidate.generation()) ); } class QXmppJingleIqContentPrivate : public QSharedData { public: QXmppJingleIqContentPrivate(); QString creator; QString disposition; QString name; QString senders; QString descriptionMedia; quint32 descriptionSsrc; QString descriptionType; QString transportType; QString transportUser; QString transportPassword; QByteArray transportFingerprint; QString transportFingerprintHash; QString transportFingerprintSetup; QList payloadTypes; QList transportCandidates; }; QXmppJingleIqContentPrivate::QXmppJingleIqContentPrivate() : descriptionSsrc(0) { } /// Constructs an empty content. QXmppJingleIq::Content::Content() : d(new QXmppJingleIqContentPrivate()) { } /// Constructs a copy of other. /// /// \param other QXmppJingleIq::Content::Content(const QXmppJingleIq::Content &other) : d(other.d) { } /// Assigns the other content to this one. /// /// \param other QXmppJingleIq::Content& QXmppJingleIq::Content::operator=(const QXmppJingleIq::Content& other) { d = other.d; return *this; } QXmppJingleIq::Content::~Content() { } QString QXmppJingleIq::Content::creator() const { return d->creator; } void QXmppJingleIq::Content::setCreator(const QString &creator) { d->creator = creator; } QString QXmppJingleIq::Content::name() const { return d->name; } void QXmppJingleIq::Content::setName(const QString &name) { d->name = name; } QString QXmppJingleIq::Content::senders() const { return d->senders; } void QXmppJingleIq::Content::setSenders(const QString &senders) { d->senders = senders; } QString QXmppJingleIq::Content::descriptionMedia() const { return d->descriptionMedia; } void QXmppJingleIq::Content::setDescriptionMedia(const QString &media) { d->descriptionMedia = media; } quint32 QXmppJingleIq::Content::descriptionSsrc() const { return d->descriptionSsrc; } void QXmppJingleIq::Content::setDescriptionSsrc(quint32 ssrc) { d->descriptionSsrc = ssrc; } void QXmppJingleIq::Content::addPayloadType(const QXmppJinglePayloadType &payload) { d->descriptionType = ns_jingle_rtp; d->payloadTypes << payload; } QList QXmppJingleIq::Content::payloadTypes() const { return d->payloadTypes; } void QXmppJingleIq::Content::setPayloadTypes(const QList &payloadTypes) { d->descriptionType = payloadTypes.isEmpty() ? QString() : ns_jingle_rtp; d->payloadTypes = payloadTypes; } void QXmppJingleIq::Content::addTransportCandidate(const QXmppJingleCandidate &candidate) { d->transportType = ns_jingle_ice_udp; d->transportCandidates << candidate; } QList QXmppJingleIq::Content::transportCandidates() const { return d->transportCandidates; } void QXmppJingleIq::Content::setTransportCandidates(const QList &candidates) { d->transportType = candidates.isEmpty() ? QString() : ns_jingle_ice_udp; d->transportCandidates = candidates; } QString QXmppJingleIq::Content::transportUser() const { return d->transportUser; } void QXmppJingleIq::Content::setTransportUser(const QString &user) { d->transportUser = user; } QString QXmppJingleIq::Content::transportPassword() const { return d->transportPassword; } void QXmppJingleIq::Content::setTransportPassword(const QString &password) { d->transportPassword = password; } /// Returns the fingerprint hash value for the transport key. /// /// This is used for DTLS-SRTP as defined in XEP-0320. QByteArray QXmppJingleIq::Content::transportFingerprint() const { return d->transportFingerprint; } /// Sets the fingerprint hash value for the transport key. /// /// This is used for DTLS-SRTP as defined in XEP-0320. void QXmppJingleIq::Content::setTransportFingerprint(const QByteArray &fingerprint) { d->transportFingerprint = fingerprint; } /// Returns the fingerprint hash algorithm for the transport key. /// /// This is used for DTLS-SRTP as defined in XEP-0320. QString QXmppJingleIq::Content::transportFingerprintHash() const { return d->transportFingerprintHash; } /// Sets the fingerprint hash algorithm for the transport key. /// /// This is used for DTLS-SRTP as defined in XEP-0320. void QXmppJingleIq::Content::setTransportFingerprintHash(const QString &hash) { d->transportFingerprintHash = hash; } /// Returns the setup role for the encrypted transport. /// /// This is used for DTLS-SRTP as defined in XEP-0320. QString QXmppJingleIq::Content::transportFingerprintSetup() const { return d->transportFingerprintSetup; } /// Sets the setup role for the encrypted transport. /// /// This is used for DTLS-SRTP as defined in XEP-0320. void QXmppJingleIq::Content::setTransportFingerprintSetup(const QString &setup) { d->transportFingerprintSetup = setup; } /// \cond void QXmppJingleIq::Content::parse(const QDomElement &element) { d->creator = element.attribute("creator"); d->disposition = element.attribute("disposition"); d->name = element.attribute("name"); d->senders = element.attribute("senders"); // description QDomElement descriptionElement = element.firstChildElement("description"); d->descriptionType = descriptionElement.namespaceURI(); d->descriptionMedia = descriptionElement.attribute("media"); d->descriptionSsrc = descriptionElement.attribute("ssrc").toULong(); QDomElement child = descriptionElement.firstChildElement("payload-type"); while (!child.isNull()) { QXmppJinglePayloadType payload; payload.parse(child); d->payloadTypes << payload; child = child.nextSiblingElement("payload-type"); } // transport QDomElement transportElement = element.firstChildElement("transport"); d->transportType = transportElement.namespaceURI(); d->transportUser = transportElement.attribute("ufrag"); d->transportPassword = transportElement.attribute("pwd"); child = transportElement.firstChildElement("candidate"); while (!child.isNull()) { QXmppJingleCandidate candidate; candidate.parse(child); d->transportCandidates << candidate; child = child.nextSiblingElement("candidate"); } child = transportElement.firstChildElement("fingerprint"); /// XEP-0320 if (!child.isNull()) { d->transportFingerprint = parseFingerprint(child.text()); d->transportFingerprintHash = child.attribute("hash"); d->transportFingerprintSetup = child.attribute("setup"); } } void QXmppJingleIq::Content::toXml(QXmlStreamWriter *writer) const { if (d->creator.isEmpty() || d->name.isEmpty()) return; writer->writeStartElement("content"); helperToXmlAddAttribute(writer, "creator", d->creator); helperToXmlAddAttribute(writer, "disposition", d->disposition); helperToXmlAddAttribute(writer, "name", d->name); helperToXmlAddAttribute(writer, "senders", d->senders); // description if (!d->descriptionType.isEmpty() || !d->payloadTypes.isEmpty()) { writer->writeStartElement("description"); writer->writeAttribute("xmlns", d->descriptionType); helperToXmlAddAttribute(writer, "media", d->descriptionMedia); if (d->descriptionSsrc) writer->writeAttribute("ssrc", QString::number(d->descriptionSsrc)); foreach (const QXmppJinglePayloadType &payload, d->payloadTypes) payload.toXml(writer); writer->writeEndElement(); } // transport if (!d->transportType.isEmpty() || !d->transportCandidates.isEmpty()) { writer->writeStartElement("transport"); writer->writeAttribute("xmlns", d->transportType); helperToXmlAddAttribute(writer, "ufrag", d->transportUser); helperToXmlAddAttribute(writer, "pwd", d->transportPassword); foreach (const QXmppJingleCandidate &candidate, d->transportCandidates) candidate.toXml(writer); // XEP-0320 if (!d->transportFingerprint.isEmpty() && !d->transportFingerprintHash.isEmpty()) { writer->writeStartElement("fingerprint"); writer->writeAttribute("xmlns", ns_jingle_dtls); writer->writeAttribute("hash", d->transportFingerprintHash); writer->writeAttribute("setup", d->transportFingerprintSetup); writer->writeCharacters(formatFingerprint(d->transportFingerprint)); writer->writeEndElement(); } writer->writeEndElement(); } writer->writeEndElement(); } bool QXmppJingleIq::Content::parseSdp(const QString &sdp) { QList payloads; QString line; foreach (line, sdp.split('\n')) { if (line.endsWith('\r')) line.resize(line.size() - 1); if (line.startsWith("a=")) { int idx = line.indexOf(':'); const QString attrName = idx != -1 ? line.mid(2, idx - 2) : line.mid(2); const QString attrValue = idx != -1 ? line.mid(idx + 1) : ""; if (attrName == "candidate") { QXmppJingleCandidate candidate; if (!candidateParseSdp(&candidate, line.mid(2))) { qWarning() << "Could not parse candidate" << line; return false; } addTransportCandidate(candidate); } else if (attrName == "fingerprint") { const QStringList bits = attrValue.split(' '); if (bits.size() > 1) { d->transportFingerprintHash = bits[0]; d->transportFingerprint = parseFingerprint(bits[1]); } } else if (attrName == "fmtp") { int spIdx = attrValue.indexOf(' '); if (spIdx == -1) { qWarning() << "Could not parse payload parameters" << line; return false; } const int id = attrValue.left(spIdx).toInt(); const QString paramStr = attrValue.mid(spIdx + 1); for (int i = 0; i < payloads.size(); ++i) { if (payloads[i].id() == id) { QMap params; if (payloads[i].name() == "telephone-event") { params.insert("events", paramStr); } else { foreach (const QString p, paramStr.split(QRegExp(";\\s*"))) { QStringList bits = p.split('='); if (bits.size() == 2) params.insert(bits[0], bits[1]); } } payloads[i].setParameters(params); } } } else if (attrName == "rtpmap") { // payload type map const QStringList bits = attrValue.split(' '); if (bits.size() != 2) continue; bool ok = false; const int id = bits[0].toInt(&ok); if (!ok) continue; const QStringList args = bits[1].split('/'); for (int i = 0; i < payloads.size(); ++i) { if (payloads[i].id() == id) { payloads[i].setName(args[0]); if (args.size() > 1) payloads[i].setClockrate(args[1].toInt()); if (args.size() > 2) payloads[i].setChannels(args[2].toInt()); } } } else if (attrName == "ice-ufrag") { d->transportUser = attrValue; } else if (attrName == "ice-pwd") { d->transportPassword = attrValue; } else if (attrName == "setup") { d->transportFingerprintSetup = attrValue; } else if (attrName == "ssrc") { const QStringList bits = attrValue.split(' '); if (bits.isEmpty()) { qWarning() << "Could not parse ssrc" << line; return false; } d->descriptionSsrc = bits[0].toULong(); } } else if (line.startsWith("m=")) { // FIXME: what do we do with the profile (bits[2]) ? QStringList bits = line.mid(2).split(' '); if (bits.size() < 3) { qWarning() << "Could not parse media" << line; return false; } d->descriptionMedia = bits[0]; // parse payload types for (int i = 3; i < bits.size(); ++i) { bool ok = false; int id = bits[i].toInt(&ok); if (!ok) continue; QXmppJinglePayloadType payload; payload.setId(id); payloads << payload; } } } setPayloadTypes(payloads); return true; } static bool candidateLessThan(const QXmppJingleCandidate &c1, const QXmppJingleCandidate &c2) { if (c1.type() == c2.type()) return c1.priority() > c2.priority(); else return c1.type() == QXmppJingleCandidate::ServerReflexiveType; } QString QXmppJingleIq::Content::toSdp() const { // get default candidate QHostAddress localRtpAddress = QHostAddress::Any; quint16 localRtpPort = 0; QList sortedCandidates = d->transportCandidates; qSort(sortedCandidates.begin(), sortedCandidates.end(), candidateLessThan); foreach (const QXmppJingleCandidate &candidate, sortedCandidates) { if (candidate.component() == RTP_COMPONENT) { localRtpAddress = candidate.host(); localRtpPort = candidate.port(); break; } } QStringList sdp; // media QString payloads; QStringList attrs; foreach (const QXmppJinglePayloadType &payload, d->payloadTypes) { payloads += " " + QString::number(payload.id()); QString rtpmap = QString::number(payload.id()) + " " + payload.name() + "/" + QString::number(payload.clockrate()); if (payload.channels() > 1) rtpmap += "/" + QString::number(payload.channels()); attrs << "a=rtpmap:" + rtpmap; // payload parameters QStringList paramList; const QMap params = payload.parameters(); if (payload.name() == "telephone-event") { if (params.contains("events")) paramList << params.value("events"); } else { QMap::const_iterator i; for (i = params.begin(); i != params.end(); ++i) paramList << i.key() + "=" + i.value(); } if (!paramList.isEmpty()) attrs << "a=fmtp:" + QByteArray::number(payload.id()) + " " + paramList.join("; "); } sdp << QString("m=%1 %2 RTP/AVP%3").arg(d->descriptionMedia, QString::number(localRtpPort), payloads); sdp << QString("c=%1").arg(addressToSdp(localRtpAddress)); sdp += attrs; // transport foreach (const QXmppJingleCandidate &candidate, d->transportCandidates) sdp << QString("a=%1").arg(candidateToSdp(candidate)); if (!d->transportUser.isEmpty()) sdp << QString("a=ice-ufrag:%1").arg(d->transportUser); if (!d->transportPassword.isEmpty()) sdp << QString("a=ice-pwd:%1").arg(d->transportPassword); if (!d->transportFingerprint.isEmpty() && !d->transportFingerprintHash.isEmpty()) sdp << QString("a=fingerprint:%1 %2").arg( d->transportFingerprintHash, formatFingerprint(d->transportFingerprint)); if (!d->transportFingerprintSetup.isEmpty()) sdp << QString("a=setup:%1").arg(d->transportFingerprintSetup); return sdp.join("\r\n") + "\r\n"; } /// \endcond QXmppJingleIq::Reason::Reason() : m_type(None) { } /// Returns the reason's textual description. QString QXmppJingleIq::Reason::text() const { return m_text; } /// Sets the reason's textual description. void QXmppJingleIq::Reason::setText(const QString &text) { m_text = text; } /// Gets the reason's type. QXmppJingleIq::Reason::Type QXmppJingleIq::Reason::type() const { return m_type; } /// Sets the reason's type. void QXmppJingleIq::Reason::setType(QXmppJingleIq::Reason::Type type) { m_type = type; } /// \cond 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(); } /// \endcond class QXmppJingleIqPrivate : public QSharedData { public: QXmppJingleIqPrivate(); QXmppJingleIq::Action action; QString initiator; QString responder; QString sid; QList contents; QXmppJingleIq::Reason reason; bool ringing; }; QXmppJingleIqPrivate::QXmppJingleIqPrivate() : ringing(false) { } /// Constructs a QXmppJingleIq. QXmppJingleIq::QXmppJingleIq() : d(new QXmppJingleIqPrivate()) { } /// Constructs a copy of other. /// /// \param other QXmppJingleIq::QXmppJingleIq(const QXmppJingleIq &other) : QXmppIq(other) , d(other.d) { } QXmppJingleIq::~QXmppJingleIq() { } /// Assigns the other Jingle IQ to this one. /// /// \param other QXmppJingleIq& QXmppJingleIq::operator=(const QXmppJingleIq& other) { d = other.d; return *this; } /// Returns the Jingle IQ's action. QXmppJingleIq::Action QXmppJingleIq::action() const { return d->action; } /// Sets the Jingle IQ's action. /// /// \param action void QXmppJingleIq::setAction(QXmppJingleIq::Action action) { d->action = action; } /// Adds an element to the IQ's content elements. void QXmppJingleIq::addContent(const QXmppJingleIq::Content &content) { d->contents << content; } /// Returns the IQ's content elements. QList QXmppJingleIq::contents() const { return d->contents; } /// Sets the IQ's content elements. void QXmppJingleIq::setContents(const QList &contents) { d->contents = contents; } /// Returns the session initiator. QString QXmppJingleIq::initiator() const { return d->initiator; } /// Sets the session initiator. /// /// \param initiator void QXmppJingleIq::setInitiator(const QString &initiator) { d->initiator = initiator; } /// Returns a reference to the IQ's reason element. QXmppJingleIq::Reason& QXmppJingleIq::reason() { return d->reason; } /// Returns a const reference to the IQ's reason element. const QXmppJingleIq::Reason& QXmppJingleIq::reason() const { return d->reason; } /// Returns the session responder. QString QXmppJingleIq::responder() const { return d->responder; } /// Sets the session responder. /// /// \param responder void QXmppJingleIq::setResponder(const QString &responder) { d->responder = responder; } /// Returns true if the call is ringing. bool QXmppJingleIq::ringing() const { return d->ringing; } /// Set to true if the call is ringing. /// /// \param ringing void QXmppJingleIq::setRinging(bool ringing) { d->ringing = ringing; } /// Returns the session ID. QString QXmppJingleIq::sid() const { return d->sid; } /// Sets the session ID. /// /// \param sid void QXmppJingleIq::setSid(const QString &sid) { d->sid = sid; } /// \cond bool QXmppJingleIq::isJingleIq(const QDomElement &element) { QDomElement jingleElement = element.firstChildElement("jingle"); return (jingleElement.namespaceURI() == ns_jingle); } 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]) { d->action = static_cast(i); break; } } d->initiator = jingleElement.attribute("initiator"); d->responder = jingleElement.attribute("responder"); d->sid = jingleElement.attribute("sid"); // content d->contents.clear(); QDomElement contentElement = jingleElement.firstChildElement("content"); while (!contentElement.isNull()) { QXmppJingleIq::Content content; content.parse(contentElement); addContent(content); contentElement = contentElement.nextSiblingElement("content"); } QDomElement reasonElement = jingleElement.firstChildElement("reason"); d->reason.parse(reasonElement); // ringing QDomElement ringingElement = jingleElement.firstChildElement("ringing"); d->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[d->action]); helperToXmlAddAttribute(writer, "initiator", d->initiator); helperToXmlAddAttribute(writer, "responder", d->responder); helperToXmlAddAttribute(writer, "sid", d->sid); foreach (const QXmppJingleIq::Content &content, d->contents) content.toXml(writer); d->reason.toXml(writer); // ringing if (d->ringing) { writer->writeStartElement("ringing"); writer->writeAttribute("xmlns", ns_jingle_rtp_info); writer->writeEndElement(); } writer->writeEndElement(); } /// \endcond class QXmppJingleCandidatePrivate : public QSharedData { public: QXmppJingleCandidatePrivate(); int component; QString foundation; int generation; QHostAddress host; QString id; int network; quint16 port; QString protocol; int priority; QXmppJingleCandidate::Type type; }; QXmppJingleCandidatePrivate::QXmppJingleCandidatePrivate() : component(0) , generation(0) , network(0) , port(0) , priority(0) , type(QXmppJingleCandidate::HostType) { } /// Constructs an empty candidate. QXmppJingleCandidate::QXmppJingleCandidate() : d(new QXmppJingleCandidatePrivate()) { } /// Constructs a copy of other. /// /// \param other QXmppJingleCandidate::QXmppJingleCandidate(const QXmppJingleCandidate &other) : d(other.d) { } QXmppJingleCandidate::~QXmppJingleCandidate() { } /// Assigns the other candidate to this one. /// /// \param other QXmppJingleCandidate& QXmppJingleCandidate::operator=(const QXmppJingleCandidate& other) { d = other.d; return *this; } /// Returns the candidate's component ID. int QXmppJingleCandidate::component() const { return d->component; } /// Sets the candidates's component ID. /// /// \param component void QXmppJingleCandidate::setComponent(int component) { d->component = component; } /// Returns the candidate's foundation. QString QXmppJingleCandidate::foundation() const { return d->foundation; } /// Sets the candidate's foundation. /// /// \param foundation void QXmppJingleCandidate::setFoundation(const QString &foundation) { d->foundation = foundation; } /// Returns the candidate's generation. int QXmppJingleCandidate::generation() const { return d->generation; } /// Sets the candidate's generation. /// /// \param generation void QXmppJingleCandidate::setGeneration(int generation) { d->generation = generation; } /// Returns the candidate's host address. /// QHostAddress QXmppJingleCandidate::host() const { return d->host; } /// Sets the candidate's host address. /// /// \param host void QXmppJingleCandidate::setHost(const QHostAddress &host) { d->host = host; } /// Returns the candidate's unique identifier. /// QString QXmppJingleCandidate::id() const { return d->id; } /// Sets the candidate's unique identifier. /// /// \param id void QXmppJingleCandidate::setId(const QString &id) { d->id = id; } /// Returns the network index (starting at 0) the candidate is on. /// int QXmppJingleCandidate::network() const { return d->network; } /// Sets the network index (starting at 0) the candidate is on. /// /// \param network void QXmppJingleCandidate::setNetwork(int network) { d->network = network; } /// Returns the candidate's port number. /// quint16 QXmppJingleCandidate::port() const { return d->port; } /// Sets the candidate's port number. /// /// \param port void QXmppJingleCandidate::setPort(quint16 port) { d->port = port; } /// Returns the candidate's priority. /// int QXmppJingleCandidate::priority() const { return d->priority; } /// Sets the candidate's priority. /// /// \param priority void QXmppJingleCandidate::setPriority(int priority) { d->priority = priority; } /// Returns the candidate's protocol (e.g. "udp"). /// QString QXmppJingleCandidate::protocol() const { return d->protocol; } /// Sets the candidate's protocol (e.g. "udp"). /// /// \param protocol void QXmppJingleCandidate::setProtocol(const QString &protocol) { d->protocol = protocol; } /// Returns the candidate type (e.g. "host"). /// QXmppJingleCandidate::Type QXmppJingleCandidate::type() const { return d->type; } /// Sets the candidate type (e.g. "host"). /// /// \param type void QXmppJingleCandidate::setType(QXmppJingleCandidate::Type type) { d->type = type; } /// Returns true if the host address or port are empty. /// bool QXmppJingleCandidate::isNull() const { return d->host.isNull() || !d->port; } /// \cond void QXmppJingleCandidate::parse(const QDomElement &element) { d->component = element.attribute("component").toInt(); d->foundation = element.attribute("foundation"); d->generation = element.attribute("generation").toInt(); d->host = QHostAddress(element.attribute("ip")); d->id = element.attribute("id"); d->network = element.attribute("network").toInt(); d->port = element.attribute("port").toInt(); d->priority = element.attribute("priority").toInt(); d->protocol = element.attribute("protocol"); d->type = typeFromString(element.attribute("type")); } void QXmppJingleCandidate::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement("candidate"); helperToXmlAddAttribute(writer, "component", QString::number(d->component)); helperToXmlAddAttribute(writer, "foundation", d->foundation); helperToXmlAddAttribute(writer, "generation", QString::number(d->generation)); helperToXmlAddAttribute(writer, "id", d->id); helperToXmlAddAttribute(writer, "ip", d->host.toString()); helperToXmlAddAttribute(writer, "network", QString::number(d->network)); helperToXmlAddAttribute(writer, "port", QString::number(d->port)); helperToXmlAddAttribute(writer, "priority", QString::number(d->priority)); helperToXmlAddAttribute(writer, "protocol", d->protocol); helperToXmlAddAttribute(writer, "type", typeToString(d->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; } /// \endcond class QXmppJinglePayloadTypePrivate : public QSharedData { public: QXmppJinglePayloadTypePrivate(); unsigned char channels; unsigned int clockrate; unsigned char id; unsigned int maxptime; QString name; QMap parameters; unsigned int ptime; }; QXmppJinglePayloadTypePrivate::QXmppJinglePayloadTypePrivate() : channels(1) , clockrate(0) , id(0) , maxptime(0) , ptime(0) { } QXmppJinglePayloadType::QXmppJinglePayloadType() : d(new QXmppJinglePayloadTypePrivate()) { } /// Constructs a copy of other. /// /// \param other QXmppJinglePayloadType::QXmppJinglePayloadType(const QXmppJinglePayloadType &other) : d(other.d) { } QXmppJinglePayloadType::~QXmppJinglePayloadType() { } /// Returns the number of channels (e.g. 1 for mono, 2 for stereo). /// unsigned char QXmppJinglePayloadType::channels() const { return d->channels; } /// Sets the number of channels (e.g. 1 for mono, 2 for stereo). /// /// \param channels void QXmppJinglePayloadType::setChannels(unsigned char channels) { d->channels = channels; } /// Returns the clockrate in Hz, i.e. the number of samples per second. /// unsigned int QXmppJinglePayloadType::clockrate() const { return d->clockrate; } /// Sets the clockrate in Hz, i.e. the number of samples per second. /// /// \param clockrate void QXmppJinglePayloadType::setClockrate(unsigned int clockrate) { d->clockrate = clockrate; } /// Returns the payload type identifier. /// unsigned char QXmppJinglePayloadType::id() const { return d->id; } /// Sets the payload type identifier. /// void QXmppJinglePayloadType::setId(unsigned char id) { Q_ASSERT(id <= 127); d->id = id; } /// Returns the maximum packet time in milliseconds. /// unsigned int QXmppJinglePayloadType::maxptime() const { return d->maxptime; } /// Sets the maximum packet type in milliseconds. /// /// \param maxptime void QXmppJinglePayloadType::setMaxptime(unsigned int maxptime) { d->maxptime = maxptime; } /// Returns the payload type name. /// QString QXmppJinglePayloadType::name() const { return d->name; } /// Sets the payload type name. /// /// \param name void QXmppJinglePayloadType::setName(const QString &name) { d->name = name; } /// Returns the payload parameters. QMap QXmppJinglePayloadType::parameters() const { return d->parameters; } /// Sets the payload parameters. void QXmppJinglePayloadType::setParameters(const QMap ¶meters) { d->parameters = parameters; } /// Returns the packet time in milliseconds (20 by default). /// unsigned int QXmppJinglePayloadType::ptime() const { return d->ptime ? d->ptime : 20; } /// Sets the packet time in milliseconds (20 by default). /// /// \param ptime void QXmppJinglePayloadType::setPtime(unsigned int ptime) { d->ptime = ptime; } /// \cond void QXmppJinglePayloadType::parse(const QDomElement &element) { d->id = element.attribute("id").toInt(); d->name = element.attribute("name"); d->channels = element.attribute("channels").toInt(); if (!d->channels) d->channels = 1; d->clockrate = element.attribute("clockrate").toInt(); d->maxptime = element.attribute("maxptime").toInt(); d->ptime = element.attribute("ptime").toInt(); QDomElement child = element.firstChildElement("parameter"); while (!child.isNull()) { d->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(d->id)); helperToXmlAddAttribute(writer, "name", d->name); if (d->channels > 1) helperToXmlAddAttribute(writer, "channels", QString::number(d->channels)); if (d->clockrate > 0) helperToXmlAddAttribute(writer, "clockrate", QString::number(d->clockrate)); if (d->maxptime > 0) helperToXmlAddAttribute(writer, "maxptime", QString::number(d->maxptime)); if (d->ptime > 0) helperToXmlAddAttribute(writer, "ptime", QString::number(d->ptime)); foreach (const QString &key, d->parameters.keys()) { writer->writeStartElement("parameter"); writer->writeAttribute("name", key); writer->writeAttribute("value", d->parameters.value(key)); writer->writeEndElement(); } writer->writeEndElement(); } /// \endcond /// Assigns the other payload type to this one. /// /// \param other QXmppJinglePayloadType& QXmppJinglePayloadType::operator=(const QXmppJinglePayloadType& other) { d = other.d; return *this; } /// 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 (d->id <= 95) return other.d->id == d->id && other.d->clockrate == d->clockrate; else return other.d->channels == d->channels && other.d->clockrate == d->clockrate && other.d->name.toLower() == d->name.toLower(); } qxmpp-0.9.3/src/base/QXmppJingleIq.h000066400000000000000000000216341263006255200172410ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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" class QXmppJingleCandidatePrivate; class QXmppJingleIqContentPrivate; class QXmppJingleIqPrivate; class QXmppJinglePayloadTypePrivate; /// \brief The QXmppJinglePayloadType class represents a payload type /// as specified by XEP-0167: Jingle RTP Sessions and RFC 5245. /// class QXMPP_EXPORT QXmppJinglePayloadType { public: QXmppJinglePayloadType(); QXmppJinglePayloadType(const QXmppJinglePayloadType &other); ~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 QXmppJinglePayloadType& operator=(const QXmppJinglePayloadType &other); bool operator==(const QXmppJinglePayloadType &other) const; private: QSharedDataPointer d; }; /// \brief The QXmppJingleCandidate class represents a transport candidate /// as specified by XEP-0176: Jingle ICE-UDP Transport Method. /// class QXMPP_EXPORT 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(); QXmppJingleCandidate(const QXmppJingleCandidate &other); ~QXmppJingleCandidate(); QXmppJingleCandidate& operator=(const QXmppJingleCandidate &other); int component() const; void setComponent(int component); QString foundation() const; void setFoundation(const QString &foundation); int generation() const; void setGeneration(int generation); 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; /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; static QXmppJingleCandidate::Type typeFromString(const QString &typeStr, bool *ok = 0); static QString typeToString(QXmppJingleCandidate::Type type); /// \endcond private: QSharedDataPointer d; }; /// \brief The QXmppJingleIq class represents an IQ used for initiating media /// sessions as specified by XEP-0166: Jingle. /// /// \ingroup Stanzas class QXMPP_EXPORT 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 QXMPP_EXPORT Content { public: Content(); Content(const QXmppJingleIq::Content &other); ~Content(); Content& operator=(const Content &other); 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); quint32 descriptionSsrc() const; void setDescriptionSsrc(quint32 ssrc); void addPayloadType(const QXmppJinglePayloadType &payload); QList payloadTypes() const; void setPayloadTypes(const QList &payloadTypes); void addTransportCandidate(const QXmppJingleCandidate &candidate); QList transportCandidates() const; void setTransportCandidates(const QList &candidates); QString transportUser() const; void setTransportUser(const QString &user); QString transportPassword() const; void setTransportPassword(const QString &password); // XEP-0320: Use of DTLS-SRTP in Jingle Sessions QByteArray transportFingerprint() const; void setTransportFingerprint(const QByteArray &fingerprint); QString transportFingerprintHash() const; void setTransportFingerprintHash(const QString &hash); QString transportFingerprintSetup() const; void setTransportFingerprintSetup(const QString &setup); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; bool parseSdp(const QString &sdp); QString toSdp() const; /// \endcond private: QSharedDataPointer d; }; /// \internal /// /// The QXmppJingleIq::Reason class represents the "reason" element of a /// QXmppJingleIq. class QXMPP_EXPORT Reason { public: /// This enum is used to describe a reason's type. 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(); QXmppJingleIq(const QXmppJingleIq &other); ~QXmppJingleIq(); QXmppJingleIq& operator=(const QXmppJingleIq &other); Action action() const; void setAction(Action action); void addContent(const Content &content); QList contents() const; void setContents(const QList &contents); QString initiator() const; void setInitiator(const QString &initiator); Reason& reason(); const Reason& reason() const; QString responder() const; void setResponder(const QString &responder); // XEP-0167: Jingle RTP Sessions bool ringing() const; void setRinging(bool ringing); QString sid() const; void setSid(const QString &sid); /// \cond static bool isJingleIq(const QDomElement &element); /// \endcond protected: /// \cond void parseElementFromChild(const QDomElement &element); void toXmlElementFromChild(QXmlStreamWriter *writer) const; /// \endcond private: QSharedDataPointer d; }; #endif qxmpp-0.9.3/src/base/QXmppLogger.cpp000066400000000000000000000143321263006255200173060ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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; } static void relaySignals(QXmppLoggable *from, QXmppLoggable *to) { QObject::connect(from, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), to, SIGNAL(logMessage(QXmppLogger::MessageType,QString))); QObject::connect(from, SIGNAL(setGauge(QString,double)), to, SIGNAL(setGauge(QString,double))); QObject::connect(from, SIGNAL(updateCounter(QString,qint64)), to, SIGNAL(updateCounter(QString,qint64))); } /// Constructs a new QXmppLoggable. /// /// \param parent QXmppLoggable::QXmppLoggable(QObject *parent) : QObject(parent) { QXmppLoggable *logParent = qobject_cast(parent); if (logParent) { relaySignals(this, logParent); } } /// \cond void QXmppLoggable::childEvent(QChildEvent *event) { QXmppLoggable *child = qobject_cast(event->child()); if (!child) return; if (event->added()) { relaySignals(child, this); } else if (event->removed()) { disconnect(child, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), this, SIGNAL(logMessage(QXmppLogger::MessageType,QString))); disconnect(child, SIGNAL(setGauge(QString,double)), this, SIGNAL(setGauge(QString,double))); disconnect(child, SIGNAL(updateCounter(QString,qint64)), this, SIGNAL(updateCounter(QString,qint64))); } } /// \endcond class QXmppLoggerPrivate { public: QXmppLoggerPrivate(); QXmppLogger::LoggingType loggingType; QFile *logFile; QString logFilePath; QXmppLogger::MessageTypes messageTypes; }; QXmppLoggerPrivate::QXmppLoggerPrivate() : loggingType(QXmppLogger::NoLogging) , logFile(0) , logFilePath("QXmppClientLog.log") , messageTypes(QXmppLogger::AnyMessage) { } /// Constructs a new QXmppLogger. /// /// \param parent QXmppLogger::QXmppLogger(QObject *parent) : QObject(parent) , d(new QXmppLoggerPrivate()) { // 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; } } /// Sets the given \a gauge to \a value. /// /// NOTE: the base implementation does nothing. void QXmppLogger::setGauge(const QString &gauge, double value) { Q_UNUSED(gauge); Q_UNUSED(value); } /// Updates the given \a counter by \a amount. /// /// NOTE: the base implementation does nothing. void QXmppLogger::updateCounter(const QString &counter, qint64 amount) { Q_UNUSED(counter); Q_UNUSED(amount); } /// 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; } } qxmpp-0.9.3/src/base/QXmppLogger.h000066400000000000000000000116611263006255200167550ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 #include "QXmppGlobal.h" #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 QXMPP_EXPORT 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: virtual void setGauge(const QString &gauge, double value); virtual void updateCounter(const QString &counter, qint64 amount); 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 QXMPP_EXPORT 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: /// Sets the given \a gauge to \a value. void setGauge(const QString &gauge, double value); /// This signal is emitted to send logging messages. void logMessage(QXmppLogger::MessageType type, const QString &msg); /// Updates the given \a counter by \a amount. void updateCounter(const QString &counter, qint64 amount = 1); }; Q_DECLARE_OPERATORS_FOR_FLAGS(QXmppLogger::MessageTypes) #endif // QXMPPLOGGER_H qxmpp-0.9.3/src/base/QXmppMessage.cpp000066400000000000000000000444421263006255200174600ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppConstants.h" #include "QXmppMessage.h" #include "QXmppUtils.h" static const char* chat_states[] = { "", "active", "inactive", "gone", "composing", "paused", }; static const char* message_types[] = { "error", "normal", "chat", "groupchat", "headline" }; static const char* marker_types[] = { "", "received", "displayed", "acknowledged" }; static const char *ns_xhtml = "http://www.w3.org/1999/xhtml"; enum StampType { LegacyDelayedDelivery, // XEP-0091: Legacy Delayed Delivery DelayedDelivery // XEP-0203: Delayed Delivery }; class QXmppMessagePrivate : public QSharedData { public: QXmppMessage::Type type; QDateTime stamp; StampType stampType; QXmppMessage::State state; bool attentionRequested; QString body; QString subject; QString thread; // XEP-0071: XHTML-IM QString xhtml; // Request message receipt as per XEP-0184. QString receiptId; bool receiptRequested; // XEP-0249: Direct MUC Invitations QString mucInvitationJid; QString mucInvitationPassword; QString mucInvitationReason; // XEP-0333: Chat Markers bool markable; QXmppMessage::Marker marker; QString markedId; QString markedThread; }; /// 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) , d(new QXmppMessagePrivate) { d->type = Chat; d->stampType = DelayedDelivery; d->state = None; d->attentionRequested = false; d->body = body; d->thread = thread; d->receiptRequested = false; d->markable = false; d->marker = NoMarker; } /// Constructs a copy of \a other. QXmppMessage::QXmppMessage(const QXmppMessage &other) : QXmppStanza(other) , d(other.d) { } QXmppMessage::~QXmppMessage() { } /// Assigns \a other to this message. QXmppMessage& QXmppMessage::operator=(const QXmppMessage &other) { QXmppStanza::operator=(other); d = other.d; return *this; } /// Returns the message's body. /// QString QXmppMessage::body() const { return d->body; } /// Sets the message's body. /// /// \param body void QXmppMessage::setBody(const QString& body) { d->body = body; } /// Returns true if the user's attention is requested, as defined /// by XEP-0224: Attention. bool QXmppMessage::isAttentionRequested() const { return d->attentionRequested; } /// Sets whether the user's attention is requested, as defined /// by XEP-0224: Attention. /// /// \a param requested void QXmppMessage::setAttentionRequested(bool requested) { d->attentionRequested = requested; } /// Returns true if a delivery receipt is requested, as defined /// by XEP-0184: Message Delivery Receipts. bool QXmppMessage::isReceiptRequested() const { return d->receiptRequested; } /// Sets whether a delivery receipt is requested, as defined /// by XEP-0184: Message Delivery Receipts. /// /// \a param requested void QXmppMessage::setReceiptRequested(bool requested) { d->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 d->receiptId; } /// Make this message a delivery receipt for the message with /// the given \a id. void QXmppMessage::setReceiptId(const QString &id) { d->receiptId = id; } /// Returns the JID for a multi-user chat direct invitation as defined /// by XEP-0249: Direct MUC Invitations. QString QXmppMessage::mucInvitationJid() const { return d->mucInvitationJid; } /// Sets the JID for a multi-user chat direct invitation as defined /// by XEP-0249: Direct MUC Invitations. void QXmppMessage::setMucInvitationJid(const QString &jid) { d->mucInvitationJid = jid; } /// Returns the password for a multi-user chat direct invitation as defined /// by XEP-0249: Direct MUC Invitations. QString QXmppMessage::mucInvitationPassword() const { return d->mucInvitationPassword; } /// Sets the \a password for a multi-user chat direct invitation as defined /// by XEP-0249: Direct MUC Invitations. void QXmppMessage::setMucInvitationPassword(const QString &password) { d->mucInvitationPassword = password; } /// Returns the reason for a multi-user chat direct invitation as defined /// by XEP-0249: Direct MUC Invitations. QString QXmppMessage::mucInvitationReason() const { return d->mucInvitationReason; } /// Sets the \a reason for a multi-user chat direct invitation as defined /// by XEP-0249: Direct MUC Invitations. void QXmppMessage::setMucInvitationReason(const QString &reason) { d->mucInvitationReason = reason; } /// Returns the message's type. /// QXmppMessage::Type QXmppMessage::type() const { return d->type; } /// Sets the message's type. /// /// \param type void QXmppMessage::setType(QXmppMessage::Type type) { d->type = type; } /// Returns the message's timestamp (if any). QDateTime QXmppMessage::stamp() const { return d->stamp; } /// Sets the message's timestamp. /// /// \param stamp void QXmppMessage::setStamp(const QDateTime &stamp) { d->stamp = stamp; } /// Returns the message's chat state. /// QXmppMessage::State QXmppMessage::state() const { return d->state; } /// Sets the message's chat state. /// /// \param state void QXmppMessage::setState(QXmppMessage::State state) { d->state = state; } /// Returns the message's subject. /// QString QXmppMessage::subject() const { return d->subject; } /// Sets the message's subject. /// /// \param subject void QXmppMessage::setSubject(const QString& subject) { d->subject = subject; } /// Returns the message's thread. QString QXmppMessage::thread() const { return d->thread; } /// Sets the message's thread. /// /// \param thread void QXmppMessage::setThread(const QString& thread) { d->thread = thread; } /// Returns the message's XHTML body as defined by /// XEP-0071: XHTML-IM. QString QXmppMessage::xhtml() const { return d->xhtml; } /// Sets the message's XHTML body as defined by /// XEP-0071: XHTML-IM. void QXmppMessage::setXhtml(const QString &xhtml) { d->xhtml = xhtml; } namespace { static QList > knownMessageSubelems() { QList > result; result << qMakePair(QString("body"), QString()) << qMakePair(QString("subject"), QString()) << qMakePair(QString("thread"), QString()) << qMakePair(QString("html"), QString()) << qMakePair(QString("received"), QString(ns_message_receipts)) << qMakePair(QString("request"), QString()) << qMakePair(QString("delay"), QString()) << qMakePair(QString("attention"), QString()) << qMakePair(QString("addresses"), QString()); for (int i = QXmppMessage::Active; i <= QXmppMessage::Paused; i++) result << qMakePair(QString(chat_states[i]), QString()); return result; } } /// Returns true if a message is markable, as defined /// XEP-0333: Chat Markers. bool QXmppMessage::isMarkable() const { return d->markable; } /// Sets if the message is markable, as defined /// XEP-0333: Chat Markers. void QXmppMessage::setMarkable(const bool markable) { d->markable = markable; } /// Returns the message's marker id, as defined /// XEP-0333: Chat Markers. QString QXmppMessage::markedId() const { return d->markedId; } /// Sets the message's marker id, as defined /// XEP-0333: Chat Markers. void QXmppMessage::setMarkerId(const QString &markerId) { d->markedId = markerId; } /// Returns the message's marker thread, as defined /// XEP-0333: Chat Markers. QString QXmppMessage::markedThread() const { return d->markedThread; } /// Sets the message's marked thread, as defined /// XEP-0333: Chat Markers. void QXmppMessage::setMarkedThread(const QString &markedThread) { d->markedThread = markedThread; } /// Returns the message's marker, as defined /// XEP-0333: Chat Markers. QXmppMessage::Marker QXmppMessage::marker() const { return d->marker; } /// Sets the message's marker, as defined /// XEP-0333: Chat Markers void QXmppMessage::setMarker(const Marker marker) { d->marker = marker; } /// \cond void QXmppMessage::parse(const QDomElement &element) { QXmppStanza::parse(element); const QString type = element.attribute("type"); d->type = Normal; for (int i = Error; i <= Headline; i++) { if (type == message_types[i]) { d->type = static_cast(i); break; } } d->body = element.firstChildElement("body").text(); d->subject = element.firstChildElement("subject").text(); d->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) { d->state = static_cast(i); break; } } // XEP-0071: XHTML-IM QDomElement htmlElement = element.firstChildElement("html"); if (!htmlElement.isNull() && htmlElement.namespaceURI() == ns_xhtml_im) { QDomElement bodyElement = htmlElement.firstChildElement("body"); if (!bodyElement.isNull() && bodyElement.namespaceURI() == ns_xhtml) { QTextStream stream(&d->xhtml, QIODevice::WriteOnly); bodyElement.save(stream, 0); d->xhtml = d->xhtml.mid(d->xhtml.indexOf('>') + 1); d->xhtml.replace(" xmlns=\"http://www.w3.org/1999/xhtml\"", ""); d->xhtml.replace("", ""); d->xhtml = d->xhtml.trimmed(); } } // XEP-0184: Message Delivery Receipts QDomElement receivedElement = element.firstChildElement("received"); if (!receivedElement.isNull() && receivedElement.namespaceURI() == ns_message_receipts) { d->receiptId = receivedElement.attribute("id"); // compatibility with old-style XEP if (d->receiptId.isEmpty()) d->receiptId = id(); } else { d->receiptId = QString(); } d->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"); d->stamp = QXmppUtils::datetimeFromString(str); d->stampType = DelayedDelivery; } // XEP-0224: Attention d->attentionRequested = element.firstChildElement("attention").namespaceURI() == ns_attention; // XEP-0333: Chat Markers QDomElement markableElement = element.firstChildElement("markable"); if (!markableElement.isNull()) { d->markable = true; } // check for all the marker types QDomElement chatStateElement; QXmppMessage::Marker marker = QXmppMessage::NoMarker; for (int i = Received; i <= Acknowledged; i++) { chatStateElement = element.firstChildElement(marker_types[i]); if (!chatStateElement.isNull() && chatStateElement.namespaceURI() == ns_chat_markers) { marker = static_cast(i); break; } } // if marker is present, check it's the right ns if (!chatStateElement.isNull()) { if (chatStateElement.namespaceURI() == ns_chat_markers) { d->marker = marker; d->markedId = chatStateElement.attribute("id", QString()); d->markedThread = chatStateElement.attribute("thread", QString()); } } const QList > &knownElems = knownMessageSubelems(); QXmppElementList extensions; QDomElement xElement = element.firstChildElement(); while (!xElement.isNull()) { if (xElement.tagName() == "x") { if (xElement.namespaceURI() == ns_legacy_delayed_delivery) { // if XEP-0203 exists, XEP-0091 has no need to parse because XEP-0091 is no more standard protocol) if (d->stamp.isNull()) { // XEP-0091: Legacy Delayed Delivery const QString str = xElement.attribute("stamp"); d->stamp = QDateTime::fromString(str, "yyyyMMddThh:mm:ss"); d->stamp.setTimeSpec(Qt::UTC); d->stampType = LegacyDelayedDelivery; } } else if (xElement.namespaceURI() == ns_conference) { // XEP-0249: Direct MUC Invitations d->mucInvitationJid = xElement.attribute("jid"); d->mucInvitationPassword = xElement.attribute("password"); d->mucInvitationReason = xElement.attribute("reason"); } else { extensions << QXmppElement(xElement); } } else if (!knownElems.contains(qMakePair(xElement.tagName(), xElement.namespaceURI())) && !knownElems.contains(qMakePair(xElement.tagName(), QString()))) { // other extensions extensions << QXmppElement(xElement); } xElement = xElement.nextSiblingElement(); } 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", message_types[d->type]); if (!d->subject.isEmpty()) helperToXmlAddTextElement(xmlWriter, "subject", d->subject); if (!d->body.isEmpty()) helperToXmlAddTextElement(xmlWriter, "body", d->body); if (!d->thread.isEmpty()) helperToXmlAddTextElement(xmlWriter, "thread", d->thread); error().toXml(xmlWriter); // chat states if (d->state > None && d->state <= Paused) { xmlWriter->writeStartElement(chat_states[d->state]); xmlWriter->writeAttribute("xmlns", ns_chat_states); xmlWriter->writeEndElement(); } // XEP-0071: XHTML-IM if (!d->xhtml.isEmpty()) { xmlWriter->writeStartElement("html"); xmlWriter->writeAttribute("xmlns", ns_xhtml_im); xmlWriter->writeStartElement("body"); xmlWriter->writeAttribute("xmlns", ns_xhtml); xmlWriter->writeCharacters(""); xmlWriter->device()->write(d->xhtml.toUtf8()); xmlWriter->writeEndElement(); xmlWriter->writeEndElement(); } // time stamp if (d->stamp.isValid()) { QDateTime utcStamp = d->stamp.toUTC(); if (d->stampType == DelayedDelivery) { // XEP-0203: Delayed Delivery xmlWriter->writeStartElement("delay"); xmlWriter->writeAttribute("xmlns", ns_delayed_delivery); helperToXmlAddAttribute(xmlWriter, "stamp", QXmppUtils::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 (!d->receiptId.isEmpty()) { xmlWriter->writeStartElement("received"); xmlWriter->writeAttribute("xmlns", ns_message_receipts); xmlWriter->writeAttribute("id", d->receiptId); xmlWriter->writeEndElement(); } if (d->receiptRequested) { xmlWriter->writeStartElement("request"); xmlWriter->writeAttribute("xmlns", ns_message_receipts); xmlWriter->writeEndElement(); } // XEP-0224: Attention if (d->attentionRequested) { xmlWriter->writeStartElement("attention"); xmlWriter->writeAttribute("xmlns", ns_attention); xmlWriter->writeEndElement(); } // XEP-0249: Direct MUC Invitations if (!d->mucInvitationJid.isEmpty()) { xmlWriter->writeStartElement("x"); xmlWriter->writeAttribute("xmlns", ns_conference); xmlWriter->writeAttribute("jid", d->mucInvitationJid); if (!d->mucInvitationPassword.isEmpty()) xmlWriter->writeAttribute("password", d->mucInvitationPassword); if (!d->mucInvitationReason.isEmpty()) xmlWriter->writeAttribute("reason", d->mucInvitationReason); xmlWriter->writeEndElement(); } // XEP-0333: Chat Markers if (d->markable) { xmlWriter->writeStartElement("markable"); xmlWriter->writeAttribute("xmlns", ns_chat_markers); xmlWriter->writeEndElement(); } if (d->marker != NoMarker) { xmlWriter->writeStartElement(marker_types[d->marker]); xmlWriter->writeAttribute("xmlns", ns_chat_markers); xmlWriter->writeAttribute("id", d->markedId); if (!d->markedThread.isNull() && !d->markedThread.isEmpty()) { xmlWriter->writeAttribute("thread", d->markedThread); } xmlWriter->writeEndElement(); } // other extensions QXmppStanza::extensionsToXml(xmlWriter); xmlWriter->writeEndElement(); } /// \endcond qxmpp-0.9.3/src/base/QXmppMessage.h000066400000000000000000000072471263006255200171270ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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" class QXmppMessagePrivate; /// \brief The QXmppMessage class represents an XMPP message. /// /// \ingroup Stanzas /// class QXMPP_EXPORT 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. }; /// This enum describes a chat marker as defined by /// XEP-0333 : Char Markers enum Marker { NoMarker = 0, Received, Displayed, Acknowledged }; QXmppMessage(const QString& from = QString(), const QString& to = QString(), const QString& body = QString(), const QString& thread = QString()); QXmppMessage(const QXmppMessage &other); ~QXmppMessage(); QXmppMessage& operator=(const QXmppMessage &other); QString body() const; void setBody(const QString&); bool isAttentionRequested() const; void setAttentionRequested(bool requested); bool isReceiptRequested() const; void setReceiptRequested(bool requested); QString mucInvitationJid() const; void setMucInvitationJid(const QString &jid); QString mucInvitationPassword() const; void setMucInvitationPassword(const QString &password); QString mucInvitationReason() const; void setMucInvitationReason(const QString &reason); 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); QString xhtml() const; void setXhtml(const QString &xhtml); // XEP-0333 bool isMarkable() const; void setMarkable(const bool); QString markedId() const; void setMarkerId(const QString&); QString markedThread() const; void setMarkedThread(const QString&); Marker marker() const; void setMarker(const Marker); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; /// \endcond private: QSharedDataPointer d; }; #endif // QXMPPMESSAGE_H qxmpp-0.9.3/src/base/QXmppMucIq.cpp000066400000000000000000000174711263006255200171140ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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) { } /// Returns true if the current item is null. bool QXmppMucItem::isNull() const { return m_actor.isEmpty() && m_affiliation == UnspecifiedAffiliation && m_jid.isEmpty() && m_nick.isEmpty() && m_reason.isEmpty() && m_role == UnspecifiedRole; } /// Returns the actor for this item, for instance the admin who kicked /// a user out of a room. QString QXmppMucItem::actor() const { return m_actor; } /// Sets the \a actor for this item, for instance the admin who kicked /// a user out of a room. 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; } /// \cond 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(); } } /// \endcond /// 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; } /// Returns the reason for this item, for example the reason for kicking /// a user out of a room. QString QXmppMucItem::reason() const { return m_reason; } /// Sets the \a reason for this item, for example the reason for kicking /// a user out of a room. 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; } /// \cond 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(); } } /// \endcond /// Sets the user's role, i.e. short-lived permissions. /// /// \param role void QXmppMucItem::setRole(Role role) { m_role = role; } /// \cond 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(); } /// \endcond /// 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; } /// \cond 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(); } /// \endcond /// 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; } /// \cond 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppMucIq.h000066400000000000000000000073051263006255200165540ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPP_EXPORT 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); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; 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 QXMPP_EXPORT 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 QXMPP_EXPORT 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 qxmpp-0.9.3/src/base/QXmppNonSASLAuth.cpp000066400000000000000000000056011263006255200201250ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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) { } 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; } /// \cond 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().toLatin1()); 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppNonSASLAuth.h000066400000000000000000000030621263006255200175710ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 QXMPP_EXPORT 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 qxmpp-0.9.3/src/base/QXmppPingIq.cpp000066400000000000000000000024121263006255200172520ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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(); } qxmpp-0.9.3/src/base/QXmppPingIq.h000066400000000000000000000017311263006255200167220ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPP_EXPORT QXmppPingIq : public QXmppIq { public: QXmppPingIq(); void toXmlElementFromChild(QXmlStreamWriter *writer) const; static bool isPingIq(const QDomElement &element); }; #endif qxmpp-0.9.3/src/base/QXmppPresence.cpp000066400000000000000000000312531263006255200176340ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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" static const char* presence_types[] = { "error", "", "unavailable", "subscribe", "subscribed", "unsubscribe", "unsubscribed", "probe" }; static const char* presence_shows[] = { "", "away", "xa", "dnd", "chat", "invisible" }; class QXmppPresencePrivate : public QSharedData { public: QXmppPresence::AvailableStatusType availableStatusType; int priority; QString statusText; QXmppPresence::Type type; /// XEP-0153: vCard-Based Avatars /// photoHash: the SHA1 hash of the avatar image data itself (not the base64-encoded version) /// in accordance with RFC 3174 QByteArray photoHash; QXmppPresence::VCardUpdateType vCardUpdateType; // XEP-0115: Entity Capabilities QString capabilityHash; QString capabilityNode; QByteArray capabilityVer; // Legacy XEP-0115: Entity Capabilities QStringList capabilityExt; // XEP-0045: Multi-User Chat QXmppMucItem mucItem; QString mucPassword; QList mucStatusCodes; bool mucSupported; }; /// Constructs a QXmppPresence. /// /// \param type QXmppPresence::QXmppPresence(QXmppPresence::Type type) : d(new QXmppPresencePrivate) { d->availableStatusType = Online; d->priority = 0; d->type = type; d->mucSupported = false; d->vCardUpdateType = VCardUpdateNone; } /// Constructs a copy of \a other. QXmppPresence::QXmppPresence(const QXmppPresence &other) : QXmppStanza(other) , d(other.d) { } /// Destroys a QXmppPresence. QXmppPresence::~QXmppPresence() { } /// Assigns \a other to this presence. QXmppPresence &QXmppPresence::operator=(const QXmppPresence &other) { QXmppStanza::operator=(other); d = other.d; return *this; } /// Returns the availability status type, for instance busy or away. /// /// This will not tell you whether a contact is connected, check whether /// type() is QXmppPresence::Available instead. QXmppPresence::AvailableStatusType QXmppPresence::availableStatusType() const { return d->availableStatusType; } /// Sets the availability status type, for instance busy or away. void QXmppPresence::setAvailableStatusType(AvailableStatusType type) { d->availableStatusType = type; } /// Returns the priority level of the resource. int QXmppPresence::priority() const { return d->priority; } /// Sets the \a priority level of the resource. void QXmppPresence::setPriority(int priority) { d->priority = priority; } /// Returns the status text, a textual description of the user's status. QString QXmppPresence::statusText() const { return d->statusText; } /// Sets the status text, a textual description of the user's status. /// /// \param statusText The status text, for example "Gone fishing". void QXmppPresence::setStatusText(const QString& statusText) { d->statusText = statusText; } /// 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 d->type; } /// Sets the presence type. /// /// \param type void QXmppPresence::setType(QXmppPresence::Type type) { d->type = type; } /// \cond void QXmppPresence::parse(const QDomElement &element) { QXmppStanza::parse(element); const QString type = element.attribute("type"); for (int i = Error; i <= Probe; i++) { if (type == presence_types[i]) { d->type = static_cast(i); break; } } const QString show = element.firstChildElement("show").text(); for (int i = Online; i <= Invisible; i++) { if (show == presence_shows[i]) { d->availableStatusType = static_cast(i); break; } } d->statusText = element.firstChildElement("status").text(); d->priority = element.firstChildElement("priority").text().toInt(); QXmppElementList extensions; QDomElement xElement = element.firstChildElement(); d->vCardUpdateType = VCardUpdateNone; while(!xElement.isNull()) { // XEP-0045: Multi-User Chat if(xElement.namespaceURI() == ns_muc) { d->mucSupported = true; d->mucPassword = xElement.firstChildElement("password").text(); } else if(xElement.namespaceURI() == ns_muc_user) { QDomElement itemElement = xElement.firstChildElement("item"); d->mucItem.parse(itemElement); QDomElement statusElement = xElement.firstChildElement("status"); d->mucStatusCodes.clear(); while (!statusElement.isNull()) { d->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()) { d->photoHash = QByteArray::fromHex(photoElement.text().toLatin1()); if(d->photoHash.isEmpty()) d->vCardUpdateType = VCardUpdateNoPhoto; else d->vCardUpdateType = VCardUpdateValidPhoto; } else { d->photoHash = QByteArray(); d->vCardUpdateType = VCardUpdateNotReady; } } // XEP-0115: Entity Capabilities else if(xElement.tagName() == "c" && xElement.namespaceURI() == ns_capabilities) { d->capabilityNode = xElement.attribute("node"); d->capabilityVer = QByteArray::fromBase64(xElement.attribute("ver").toLatin1()); d->capabilityHash = xElement.attribute("hash"); d->capabilityExt = xElement.attribute("ext").split(" ", QString::SkipEmptyParts); } else if (xElement.tagName() == "addresses") { } 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", presence_types[d->type]); const QString show = presence_shows[d->availableStatusType]; if (!show.isEmpty()) helperToXmlAddTextElement(xmlWriter, "show", show); if (!d->statusText.isEmpty()) helperToXmlAddTextElement(xmlWriter, "status", d->statusText); if (d->priority != 0) helperToXmlAddTextElement(xmlWriter, "priority", QString::number(d->priority)); error().toXml(xmlWriter); // XEP-0045: Multi-User Chat if(d->mucSupported) { xmlWriter->writeStartElement("x"); xmlWriter->writeAttribute("xmlns", ns_muc); if (!d->mucPassword.isEmpty()) xmlWriter->writeTextElement("password", d->mucPassword); xmlWriter->writeEndElement(); } if(!d->mucItem.isNull() || !d->mucStatusCodes.isEmpty()) { xmlWriter->writeStartElement("x"); xmlWriter->writeAttribute("xmlns", ns_muc_user); if (!d->mucItem.isNull()) d->mucItem.toXml(xmlWriter); foreach (int code, d->mucStatusCodes) { xmlWriter->writeStartElement("status"); xmlWriter->writeAttribute("code", QString::number(code)); xmlWriter->writeEndElement(); } xmlWriter->writeEndElement(); } // XEP-0153: vCard-Based Avatars if(d->vCardUpdateType != VCardUpdateNone) { xmlWriter->writeStartElement("x"); xmlWriter->writeAttribute("xmlns", ns_vcard_update); switch(d->vCardUpdateType) { case VCardUpdateNoPhoto: helperToXmlAddTextElement(xmlWriter, "photo", ""); break; case VCardUpdateValidPhoto: helperToXmlAddTextElement(xmlWriter, "photo", d->photoHash.toHex()); break; case VCardUpdateNotReady: break; default: break; } xmlWriter->writeEndElement(); } if(!d->capabilityNode.isEmpty() && !d->capabilityVer.isEmpty() && !d->capabilityHash.isEmpty()) { xmlWriter->writeStartElement("c"); xmlWriter->writeAttribute("xmlns", ns_capabilities); helperToXmlAddAttribute(xmlWriter, "hash", d->capabilityHash); helperToXmlAddAttribute(xmlWriter, "node", d->capabilityNode); helperToXmlAddAttribute(xmlWriter, "ver", d->capabilityVer.toBase64()); xmlWriter->writeEndElement(); } // other extensions QXmppStanza::extensionsToXml(xmlWriter); xmlWriter->writeEndElement(); } /// \endcond /// Returns the photo-hash of the VCardUpdate. /// /// \return QByteArray QByteArray QXmppPresence::photoHash() const { return d->photoHash; } /// Sets the photo-hash of the VCardUpdate. /// /// \param photoHash as QByteArray void QXmppPresence::setPhotoHash(const QByteArray& photoHash) { d->photoHash = photoHash; } /// Returns the type of VCardUpdate /// /// \return VCardUpdateType QXmppPresence::VCardUpdateType QXmppPresence::vCardUpdateType() const { return d->vCardUpdateType; } /// Sets the type of VCardUpdate /// /// \param type VCardUpdateType void QXmppPresence::setVCardUpdateType(VCardUpdateType type) { d->vCardUpdateType = type; } /// XEP-0115: Entity Capabilities QString QXmppPresence::capabilityHash() const { return d->capabilityHash; } /// XEP-0115: Entity Capabilities void QXmppPresence::setCapabilityHash(const QString& hash) { d->capabilityHash = hash; } /// XEP-0115: Entity Capabilities QString QXmppPresence::capabilityNode() const { return d->capabilityNode; } /// XEP-0115: Entity Capabilities void QXmppPresence::setCapabilityNode(const QString& node) { d->capabilityNode = node; } /// XEP-0115: Entity Capabilities QByteArray QXmppPresence::capabilityVer() const { return d->capabilityVer; } /// XEP-0115: Entity Capabilities void QXmppPresence::setCapabilityVer(const QByteArray& ver) { d->capabilityVer = ver; } /// Legacy XEP-0115: Entity Capabilities QStringList QXmppPresence::capabilityExt() const { return d->capabilityExt; } /// Returns the MUC item. QXmppMucItem QXmppPresence::mucItem() const { return d->mucItem; } /// Sets the MUC item. /// /// \param item void QXmppPresence::setMucItem(const QXmppMucItem &item) { d->mucItem = item; } /// Returns the password used to join a MUC room. QString QXmppPresence::mucPassword() const { return d->mucPassword; } /// Sets the password used to join a MUC room. void QXmppPresence::setMucPassword(const QString &password) { d->mucPassword = password; } /// Returns the MUC status codes. QList QXmppPresence::mucStatusCodes() const { return d->mucStatusCodes; } /// Sets the MUC status codes. /// /// \param codes void QXmppPresence::setMucStatusCodes(const QList &codes) { d->mucStatusCodes = codes; } /// Returns true if the sender has indicated MUC support. bool QXmppPresence::isMucSupported() const { return d->mucSupported; } /// Sets whether MUC is \a supported. void QXmppPresence::setMucSupported(bool supported) { d->mucSupported = supported; } qxmpp-0.9.3/src/base/QXmppPresence.h000066400000000000000000000111611263006255200172750ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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" class QXmppPresencePrivate; /// \brief The QXmppPresence class represents an XMPP presence stanza. /// /// \ingroup Stanzas class QXMPP_EXPORT 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. }; /// This enum is used to describe an availability status. enum AvailableStatusType { Online = 0, ///< 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. Invisible ///< obsolete XEP-0018: Invisible Presence }; /// This enum is used to describe vCard updates as defined by /// 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). }; QXmppPresence(QXmppPresence::Type type = QXmppPresence::Available); QXmppPresence(const QXmppPresence &other); ~QXmppPresence(); QXmppPresence& operator=(const QXmppPresence &other); AvailableStatusType availableStatusType() const; void setAvailableStatusType(AvailableStatusType type); int priority() const; void setPriority(int priority); QXmppPresence::Type type() const; void setType(QXmppPresence::Type); QString statusText() const; void setStatusText(const QString& statusText); /// \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); QString mucPassword() const; void setMucPassword(const QString &password); QList mucStatusCodes() const; void setMucStatusCodes(const QList &codes); bool isMucSupported() const; void setMucSupported(bool supported); /// 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: QSharedDataPointer d; }; #endif // QXMPPPRESENCE_H qxmpp-0.9.3/src/base/QXmppPubSubIq.cpp000066400000000000000000000133151263006255200175610ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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; } /// \cond 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(); } /// \endcond /// 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; } /// \cond 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: case QXmppPubSubIq::RetractQuery: 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: case QXmppPubSubIq::RetractQuery: 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppPubSubIq.h000066400000000000000000000052451263006255200172310ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPP_EXPORT 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 QXMPP_EXPORT 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 qxmpp-0.9.3/src/base/QXmppRegisterIq.cpp000066400000000000000000000070371263006255200201510ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppRegisterIq.h" /// Returns the email for this registration IQ. QString QXmppRegisterIq::email() const { return m_email; } /// Sets the \a email for this registration IQ. void QXmppRegisterIq::setEmail(const QString &email) { m_email = email; } /// Returns the QXmppDataForm for this registration IQ. QXmppDataForm QXmppRegisterIq::form() const { return m_form; } /// Sets the QXmppDataForm for this registration IQ. /// /// \param form void QXmppRegisterIq::setForm(const QXmppDataForm &form) { m_form = form; } /// Returns the instructions for this registration IQ. QString QXmppRegisterIq::instructions() const { return m_instructions; } /// Sets the \a instructions for this registration IQ. void QXmppRegisterIq::setInstructions(const QString &instructions) { m_instructions = instructions; } /// Returns the password for this registration IQ. QString QXmppRegisterIq::password() const { return m_password; } /// Sets the \a password for this registration IQ. void QXmppRegisterIq::setPassword(const QString &password) { m_password = password; } /// Returns the username for this registration IQ. QString QXmppRegisterIq::username() const { return m_username; } /// Sets the \a username for this registration IQ. void QXmppRegisterIq::setUsername(const QString &username) { m_username = username; } /// \cond bool QXmppRegisterIq::isRegisterIq(const QDomElement &element) { return (element.firstChildElement("query").namespaceURI() == ns_register); } void QXmppRegisterIq::parseElementFromChild(const QDomElement &element) { QDomElement queryElement = element.firstChildElement("query"); m_instructions = queryElement.firstChildElement("instructions").text(); m_username = queryElement.firstChildElement("username").text(); m_password = queryElement.firstChildElement("password").text(); m_email = queryElement.firstChildElement("email").text(); m_form.parse(queryElement.firstChildElement("x")); } void QXmppRegisterIq::toXmlElementFromChild(QXmlStreamWriter *writer) const { writer->writeStartElement("query"); writer->writeAttribute("xmlns", ns_register); if (!m_instructions.isEmpty()) writer->writeTextElement("instructions", m_instructions); if (!m_username.isEmpty()) writer->writeTextElement("username", m_username); else if (!m_username.isNull()) writer->writeEmptyElement("username"); if (!m_password.isEmpty()) writer->writeTextElement("password", m_password); else if (!m_password.isNull()) writer->writeEmptyElement("password"); if (!m_email.isEmpty()) writer->writeTextElement("email", m_email); else if (!m_email.isNull()) writer->writeEmptyElement("email"); m_form.toXml(writer); writer->writeEndElement(); } /// \endcond qxmpp-0.9.3/src/base/QXmppRegisterIq.h000066400000000000000000000035131263006255200176110ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPREGISTERIQ_H #define QXMPPREGISTERIQ_H #include "QXmppDataForm.h" #include "QXmppIq.h" /// \brief The QXmppRegisterIq class represents a registration IQ /// as defined by XEP-0077: In-Band Registration. /// /// It is used to create an account on the server. /// /// \ingroup Stanzas class QXMPP_EXPORT QXmppRegisterIq : public QXmppIq { public: QString email() const; void setEmail(const QString &email); QXmppDataForm form() const; void setForm(const QXmppDataForm &form); QString instructions() const; void setInstructions(const QString &instructions); QString password() const; void setPassword(const QString &username); QString username() const; void setUsername(const QString &username); /// \cond static bool isRegisterIq(const QDomElement &element); /// \endcond protected: /// \cond void parseElementFromChild(const QDomElement &element); void toXmlElementFromChild(QXmlStreamWriter *writer) const; /// \endcond private: QXmppDataForm m_form; QString m_email; QString m_instructions; QString m_password; QString m_username; }; #endif qxmpp-0.9.3/src/base/QXmppResultSet.cpp000066400000000000000000000147601263006255200200260ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Olivier Goffart * * Source: * https://github.com/qxmpp-project/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 "QXmppResultSet.h" #include "QXmppUtils.h" #include #include QXmppResultSetQuery::QXmppResultSetQuery() : m_index(-1) , m_max(-1) {} /// Returns the maximum number of results. /// /// \note -1 means no limit, 0 means no results are wanted. /// int QXmppResultSetQuery::max() const { return m_max; } /// Sets the maximum number of results. /// /// \note -1 means no limit, 0 means no results are wanted. void QXmppResultSetQuery::setMax(int max) { m_max = max; } /// Returns the index for the first element in the page. /// /// This is used for retrieving pages out of order. int QXmppResultSetQuery::index() const { return m_index; } /// Sets the index for the first element in the page. /// /// This is used for retrieving pages out of order. void QXmppResultSetQuery::setIndex(int index) { m_index=index; } /// Returns the UID of the first result in the next page. /// /// This is used for for paging backwards through results. QString QXmppResultSetQuery::before() const { return m_before; } /// Sets the UID of the first result in the next page. /// /// This is used for for paging backwards through results. void QXmppResultSetQuery::setBefore(const QString& before) { m_before=before; } /// Returns the UID of the last result in the previous page. /// /// This is used for for paging forwards through results. QString QXmppResultSetQuery::after() const { return m_after; } /// Sets the UID of the last result in the previous page. /// /// This is used for for paging forwards through results. void QXmppResultSetQuery::setAfter(const QString& after) { m_after=after; } /// Returns true if no result set information is present. bool QXmppResultSetQuery::isNull() const { return m_max == -1 && m_index == -1 && m_after.isNull() && m_before.isNull(); } /// \cond void QXmppResultSetQuery::parse(const QDomElement& element) { QDomElement setElement = (element.tagName() == "set") ? element : element.firstChildElement("set"); if (setElement.namespaceURI() == ns_rsm) { bool ok = false; m_max = setElement.firstChildElement("max").text().toInt(&ok); if (!ok) m_max = -1; m_after = setElement.firstChildElement("after").text(); m_before = setElement.firstChildElement("before").text(); m_index = setElement.firstChildElement("index").text().toInt(&ok); if (!ok) m_index = -1; } } void QXmppResultSetQuery::toXml(QXmlStreamWriter* writer) const { if (isNull()) return; writer->writeStartElement("set"); writer->writeAttribute("xmlns", ns_rsm); if (m_max >= 0) helperToXmlAddTextElement(writer, "max", QString::number(m_max)); if (!m_after.isNull()) helperToXmlAddTextElement(writer, "after", m_after); if (!m_before.isNull()) helperToXmlAddTextElement(writer, "before", m_before); if (m_index >= 0) helperToXmlAddTextElement(writer, "index", QString::number(m_index)); writer->writeEndElement(); } /// \endcond QXmppResultSetReply::QXmppResultSetReply() : m_count(-1) , m_index(-1) {} /// Returns the UID of the first result in the page. QString QXmppResultSetReply::first() const { return m_first; } /// Sets the UID of the first result in the page. void QXmppResultSetReply::setFirst(const QString& first) { m_first=first; } /// Returns the UID of the last result in the page. QString QXmppResultSetReply::last() const { return m_last; } /// Sets the UID of the last result in the page. void QXmppResultSetReply::setLast(const QString& last) { m_last=last; } /// Returns the total number of items in the set. /// /// \note This may be an approximate count. int QXmppResultSetReply::count() const { return m_count; } /// Sets the total number of items in the set. /// /// \note This may be an approximate count. void QXmppResultSetReply::setCount(int count) { m_count = count; } /// Returns the index for the first result in the page. /// /// This is used for retrieving pages out of order. /// /// \note This may be an approximate index. int QXmppResultSetReply::index() const { return m_index; } /// Sets the index for the first result in the page. /// /// This is used for retrieving pages out of order. /// /// \note This may be an approximate index. void QXmppResultSetReply::setIndex(int index) { m_index = index; } /// Returns true if no result set information is present. bool QXmppResultSetReply::isNull() const { return m_count == -1 && m_index == -1 && m_first.isNull() && m_last.isNull(); } /// \cond void QXmppResultSetReply::parse(const QDomElement& element) { QDomElement setElement = (element.tagName() == "set") ? element : element.firstChildElement("set"); if (setElement.namespaceURI() == ns_rsm) { m_count = setElement.firstChildElement("count").text().toInt(); QDomElement firstElem = setElement.firstChildElement("first"); m_first = firstElem.text(); bool ok = false; m_index = firstElem.attribute("index").toInt(&ok); if(!ok) m_index = -1; m_last = setElement.firstChildElement("last").text(); } } void QXmppResultSetReply::toXml(QXmlStreamWriter* writer) const { if (isNull()) return; writer->writeStartElement("set"); writer->writeAttribute("xmlns", ns_rsm); if (!m_first.isNull() || m_index >= 0) { writer->writeStartElement("first"); if (m_index >= 0) writer->writeAttribute("index", QString::number(m_index)); writer->writeCharacters(m_first); writer->writeEndElement(); } if (!m_last.isNull()) helperToXmlAddTextElement(writer, "last", m_last); if (m_count >= 0) helperToXmlAddTextElement(writer, "count", QString::number(m_count)); writer->writeEndElement(); } /// \endcond qxmpp-0.9.3/src/base/QXmppResultSet.h000066400000000000000000000042771263006255200174750ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Olivier Goffart * * Source: * https://github.com/qxmpp-project/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 QXMPPRESULTSET_H #define QXMPPRESULTSET_H #include #include "QXmppStanza.h" /// \brief The QXmppResultSetQuery class represents a set element in a query /// as defined by XEP-0059: Result Set Management. class QXMPP_EXPORT QXmppResultSetQuery { public: QXmppResultSetQuery(); int max() const; void setMax(int max); int index() const; void setIndex(int index); QString before() const; void setBefore(const QString &before ); QString after() const; void setAfter(const QString &after ); bool isNull() const; /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; /// \endcond private: int m_index; int m_max; QString m_after; QString m_before; }; /// \brief The QXmppResultSetReply class represents a set element in a reply /// as defined by XEP-0059: Result Set Management. class QXMPP_EXPORT QXmppResultSetReply { public: QXmppResultSetReply(); QString first() const; void setFirst(const QString &first ); QString last() const; void setLast(const QString &last ); int count() const; void setCount(int count); int index() const; void setIndex(int index); bool isNull() const; /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; /// \endcond private: int m_count; int m_index; QString m_first; QString m_last; }; #endif // QXMPPRESULTSET_H qxmpp-0.9.3/src/base/QXmppRosterIq.cpp000066400000000000000000000137771263006255200176530ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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; } /// \cond 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(); } /// \endcond /// Constructs a new roster entry. QXmppRosterIq::Item::Item() : m_type(NotSet) { } /// 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"); } /// \cond 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppRosterIq.h000066400000000000000000000066071263006255200173120ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPP_EXPORT QXmppRosterIq : public QXmppIq { public: /// \brief The QXmppRosterIq::Item class represents a roster entry. class QXMPP_EXPORT 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 }; Item(); 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 qxmpp-0.9.3/src/base/QXmppRpcIq.cpp000066400000000000000000000304151263006255200171050ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Ian Reinhart Geiser * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXmppRpcMarshaller::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 QXmppRpcMarshaller::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; } /// \cond 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); } /// \endcond 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; } /// \cond 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 = QXmppRpcMarshaller::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 = QXmppRpcMarshaller::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; QXmppRpcMarshaller::marshall(writer, fault); writer->writeEndElement(); } else if (!m_values.isEmpty()) { writer->writeStartElement("params"); foreach (const QVariant &arg, m_values) { writer->writeStartElement("param"); QXmppRpcMarshaller::marshall(writer, arg); writer->writeEndElement(); } writer->writeEndElement(); } writer->writeEndElement(); writer->writeEndElement(); } /// \endcond 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; } /// \cond 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 = QXmppRpcMarshaller::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"); QXmppRpcMarshaller::marshall(writer, arg); writer->writeEndElement(); } writer->writeEndElement(); } writer->writeEndElement(); writer->writeEndElement(); } /// \endcond qxmpp-0.9.3/src/base/QXmppRpcIq.h000066400000000000000000000060601263006255200165510ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Ian Reinhart Geiser * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPP_EXPORT QXmppRpcMarshaller { public: static void marshall( QXmlStreamWriter *writer, const QVariant &value); static 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 QXMPP_EXPORT 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 QXMPP_EXPORT 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 QXMPP_EXPORT 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 qxmpp-0.9.3/src/base/QXmppRtcpPacket.cpp000066400000000000000000000352041263006255200201300ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppRtcpPacket.h" #define RTP_VERSION 2 enum DescriptionType { CnameType = 1, NameType = 2 }; class QXmppRtcpPacketPrivate : public QSharedData { public: QXmppRtcpPacketPrivate(); /// Number of report blocks. quint8 count; /// Payload type. quint8 type; /// Raw payload data. QByteArray payload; QString goodbyeReason; QList goodbyeSsrcs; QXmppRtcpSenderInfo senderInfo; QList receiverReports; QList sourceDescriptions; quint32 ssrc; }; class QXmppRtcpReceiverReportPrivate : public QSharedData { public: QXmppRtcpReceiverReportPrivate(); bool read(QDataStream &stream); void write(QDataStream &stream) const; quint32 ssrc; quint8 fractionLost; quint32 totalLost; quint32 highestSequence; quint32 jitter; quint32 lsr; quint32 dlsr; }; class QXmppRtcpSenderInfoPrivate : public QSharedData { public: QXmppRtcpSenderInfoPrivate(); bool read(QDataStream &stream); void write(QDataStream &stream) const; quint64 ntpStamp; quint32 rtpStamp; quint32 packetCount; quint32 octetCount; }; class QXmppRtcpSourceDescriptionPrivate : public QSharedData { public: QXmppRtcpSourceDescriptionPrivate(); bool read(QDataStream &stream); void write(QDataStream &stream) const; quint32 ssrc; QString cname; QString name; }; static bool readPadding(QDataStream &stream, int dataLength) { if (dataLength % 4) { QByteArray buffer; buffer.resize(4 - dataLength % 4); if (stream.readRawData(buffer.data(), buffer.size()) != buffer.size()) return false; if (buffer != QByteArray(buffer.size(), '\0')) return false; } return true; } static void writePadding(QDataStream &stream, int dataLength) { if (dataLength % 4) { const QByteArray buffer = QByteArray(4 - dataLength % 4, '\0'); stream.writeRawData(buffer.constData(), buffer.size()); } } /// Constructs an empty RTCP packet QXmppRtcpPacket::QXmppRtcpPacket() : d(new QXmppRtcpPacketPrivate()) { } /// Constructs a copy of other. /// /// \param other QXmppRtcpPacket::QXmppRtcpPacket(const QXmppRtcpPacket &other) : d(other.d) { } QXmppRtcpPacket::~QXmppRtcpPacket() { } /// Parses an RTCP packet. /// /// \param ba bool QXmppRtcpPacket::decode(const QByteArray &ba) { QDataStream stream(ba); return read(stream); } /// Encodes an RTCP packet. QByteArray QXmppRtcpPacket::encode() const { QByteArray ba; ba.resize(4 + d->payload.size()); QDataStream stream(&ba, QIODevice::WriteOnly); write(stream); return ba; } bool QXmppRtcpPacket::read(QDataStream &stream) { quint8 tmp, type; quint16 len; // fixed header stream >> tmp; stream >> type; stream >> len; if (stream.status() != QDataStream::Ok) return false; // check version if ((tmp >> 6) != RTP_VERSION) return false; const int payloadLength = len << 2; d->count = (tmp & 0x1f); d->type = type; d->payload.resize(payloadLength); if (stream.readRawData(d->payload.data(), payloadLength) != payloadLength) return false; QDataStream s(d->payload); d->goodbyeReason.clear(); d->goodbyeSsrcs.clear(); d->receiverReports.clear(); d->senderInfo = QXmppRtcpSenderInfo(); d->sourceDescriptions.clear(); d->ssrc = 0; if (d->type == Goodbye) { quint32 ssrc; for (int i = 0; i < d->count; ++i) { s >> ssrc; if (stream.status() != QDataStream::Ok) return false; d->goodbyeSsrcs << ssrc; } quint8 reasonLength; s >> reasonLength; if (reasonLength) { QByteArray buffer; buffer.resize(reasonLength); if (s.readRawData(buffer.data(), buffer.size()) != buffer.size()) return false; if (!readPadding(s, 1 + buffer.size())) return false; d->goodbyeReason = QString::fromUtf8(buffer); } } else if (d->type == ReceiverReport || d->type == SenderReport) { s >> d->ssrc; if (d->type == SenderReport && !d->senderInfo.d->read(s)) return false; for (int i = 0; i < d->count; ++i) { QXmppRtcpReceiverReport receiverReport; if (!receiverReport.d->read(s)) return false; d->receiverReports << receiverReport; } } else if (d->type == SourceDescription) { for (int i = 0; i < d->count; ++i) { QXmppRtcpSourceDescription desc; if (!desc.d->read(s)) return false; d->sourceDescriptions << desc; } } return true; } void QXmppRtcpPacket::write(QDataStream &stream) const { QByteArray payload; quint8 count; QDataStream s(&payload, QIODevice::WriteOnly); if (d->type == Goodbye) { count = d->goodbyeSsrcs.size(); foreach (quint32 ssrc, d->goodbyeSsrcs) s << ssrc; if (!d->goodbyeReason.isEmpty()) { const QByteArray reason = d->goodbyeReason.toUtf8(); s << quint8(reason.size()); s.writeRawData(reason.constData(), reason.size()); writePadding(s, 1 + reason.size()); } } else if (d->type == ReceiverReport || d->type == SenderReport) { count = d->receiverReports.size(); s << d->ssrc; if (d->type == SenderReport) d->senderInfo.d->write(s); foreach (const QXmppRtcpReceiverReport &report, d->receiverReports) report.d->write(s); } else if (d->type == SourceDescription) { count = d->sourceDescriptions.size(); foreach (const QXmppRtcpSourceDescription &desc, d->sourceDescriptions) desc.d->write(s); } else { count = d->count; payload = d->payload; } stream << quint8((RTP_VERSION << 6) | (count & 0x1f)); stream << d->type; stream << quint16(payload.size() >> 2); stream.writeRawData(payload.constData(), payload.size()); } QString QXmppRtcpPacket::goodbyeReason() const { return d->goodbyeReason; } void QXmppRtcpPacket::setGoodbyeReason(const QString &goodbyeReason) { d->goodbyeReason = goodbyeReason; } QList QXmppRtcpPacket::goodbyeSsrcs() const { return d->goodbyeSsrcs; } void QXmppRtcpPacket::setGoodbyeSsrcs(const QList &goodbyeSsrcs) { d->goodbyeSsrcs = goodbyeSsrcs; } QList QXmppRtcpPacket::receiverReports() const { return d->receiverReports; } void QXmppRtcpPacket::setReceiverReports(const QList &reports) { d->receiverReports = reports; } QXmppRtcpSenderInfo QXmppRtcpPacket::senderInfo() const { return d->senderInfo; } void QXmppRtcpPacket::setSenderInfo(const QXmppRtcpSenderInfo &senderInfo) { d->senderInfo = senderInfo; } QList QXmppRtcpPacket::sourceDescriptions() const { return d->sourceDescriptions; } void QXmppRtcpPacket::setSourceDescriptions(const QList &descriptions) { d->sourceDescriptions = descriptions; } /// Returns the RTCP packet's source SSRC. /// /// This is only applicable for Sender Reports or Receiver Reports. quint32 QXmppRtcpPacket::ssrc() const { return d->ssrc; } /// Sets the RTCP packet's source SSRC. /// /// This is only applicable for Sender Reports or Receiver Reports. void QXmppRtcpPacket::setSsrc(quint32 ssrc) { d->ssrc = ssrc; } /// Returns the RTCP packet type. quint8 QXmppRtcpPacket::type() const { return d->type; } /// Sets the RTCP packet type. /// /// \param type void QXmppRtcpPacket::setType(quint8 type) { d->type = type; } QXmppRtcpPacketPrivate::QXmppRtcpPacketPrivate() : count(0) , type(0) , ssrc(0) { } /// Constructs an empty receiver report. QXmppRtcpReceiverReport::QXmppRtcpReceiverReport() : d(new QXmppRtcpReceiverReportPrivate()) { } /// Constructs a copy of other. /// /// \param other QXmppRtcpReceiverReport::QXmppRtcpReceiverReport(const QXmppRtcpReceiverReport &other) : d(other.d) { } QXmppRtcpReceiverReport::~QXmppRtcpReceiverReport() { } quint32 QXmppRtcpReceiverReport::dlsr() const { return d->dlsr; } void QXmppRtcpReceiverReport::setDlsr(quint32 dlsr) { d->dlsr = dlsr; } quint8 QXmppRtcpReceiverReport::fractionLost() const { return d->fractionLost; } void QXmppRtcpReceiverReport::setFractionLost(quint8 fractionLost) { d->fractionLost = fractionLost; } quint32 QXmppRtcpReceiverReport::jitter() const { return d->jitter; } void QXmppRtcpReceiverReport::setJitter(quint32 jitter) { d->jitter = jitter; } quint32 QXmppRtcpReceiverReport::lsr() const { return d->lsr; } void QXmppRtcpReceiverReport::setLsr(quint32 lsr) { d->lsr = lsr; } quint32 QXmppRtcpReceiverReport::ssrc() const { return d->ssrc; } void QXmppRtcpReceiverReport::setSsrc(quint32 ssrc) { d->ssrc = ssrc; } quint32 QXmppRtcpReceiverReport::totalLost() const { return d->totalLost; } void QXmppRtcpReceiverReport::setTotalLost(quint32 totalLost) { d->totalLost = totalLost; } QXmppRtcpReceiverReportPrivate::QXmppRtcpReceiverReportPrivate() : ssrc(0) , fractionLost(0) , totalLost(0) , highestSequence(0) , jitter(0) , lsr(0) , dlsr(0) { } bool QXmppRtcpReceiverReportPrivate::read(QDataStream &stream) { quint32 tmp; stream >> ssrc; stream >> tmp; fractionLost = (tmp >> 24) & 0xff; totalLost = tmp & 0xffffff; stream >> highestSequence; stream >> jitter; stream >> lsr; stream >> dlsr; return stream.status() == QDataStream::Ok; } void QXmppRtcpReceiverReportPrivate::write(QDataStream &stream) const { stream << ssrc; stream << quint32((fractionLost << 24) | (totalLost & 0xffffff)); stream << highestSequence; stream << jitter; stream << lsr; stream << dlsr; } /// Constructs an empty sender report. QXmppRtcpSenderInfo::QXmppRtcpSenderInfo() : d(new QXmppRtcpSenderInfoPrivate()) { } /// Constructs a copy of other. /// /// \param other QXmppRtcpSenderInfo::QXmppRtcpSenderInfo(const QXmppRtcpSenderInfo &other) : d(other.d) { } QXmppRtcpSenderInfo::~QXmppRtcpSenderInfo() { } quint64 QXmppRtcpSenderInfo::ntpStamp() const { return d->ntpStamp; } void QXmppRtcpSenderInfo::setNtpStamp(quint64 ntpStamp) { d->ntpStamp = ntpStamp; } quint32 QXmppRtcpSenderInfo::rtpStamp() const { return d->rtpStamp; } void QXmppRtcpSenderInfo::setRtpStamp(quint32 rtpStamp) { d->rtpStamp = rtpStamp; } quint32 QXmppRtcpSenderInfo::octetCount() const { return d->octetCount; } void QXmppRtcpSenderInfo::setOctetCount(quint32 count) { d->octetCount = count; } quint32 QXmppRtcpSenderInfo::packetCount() const { return d->packetCount; } void QXmppRtcpSenderInfo::setPacketCount(quint32 count) { d->packetCount = count; } QXmppRtcpSenderInfoPrivate::QXmppRtcpSenderInfoPrivate() : ntpStamp(0) , rtpStamp(0) , packetCount(0) , octetCount(0) { } bool QXmppRtcpSenderInfoPrivate::read(QDataStream &stream) { stream >> ntpStamp; stream >> rtpStamp; stream >> packetCount; stream >> octetCount; return stream.status() == QDataStream::Ok; } void QXmppRtcpSenderInfoPrivate::write(QDataStream &stream) const { stream << ntpStamp; stream << rtpStamp; stream << packetCount; stream << octetCount; } /// Constructs an empty source description QXmppRtcpSourceDescription::QXmppRtcpSourceDescription() : d(new QXmppRtcpSourceDescriptionPrivate()) { } /// Constructs a copy of other. /// /// \param other QXmppRtcpSourceDescription::QXmppRtcpSourceDescription(const QXmppRtcpSourceDescription &other) : d(other.d) { } QXmppRtcpSourceDescription::~QXmppRtcpSourceDescription() { } QString QXmppRtcpSourceDescription::cname() const { return d->cname; } void QXmppRtcpSourceDescription::setCname(const QString &cname) { d->cname = cname; } QString QXmppRtcpSourceDescription::name() const { return d->name; } void QXmppRtcpSourceDescription::setName(const QString &name) { d->name = name; } quint32 QXmppRtcpSourceDescription::ssrc() const { return d->ssrc; } void QXmppRtcpSourceDescription::setSsrc(quint32 ssrc) { d->ssrc = ssrc; } QXmppRtcpSourceDescriptionPrivate::QXmppRtcpSourceDescriptionPrivate() : ssrc(0) { } bool QXmppRtcpSourceDescriptionPrivate::read(QDataStream &stream) { QByteArray buffer; quint8 itemType, itemLength; quint16 chunkLength = 0; stream >> ssrc; if (stream.status() != QDataStream::Ok) return false; while (true) { stream >> itemType; if (stream.status() != QDataStream::Ok) return false; if (!itemType) { chunkLength++; break; } stream >> itemLength; if (stream.status() != QDataStream::Ok) return false; buffer.resize(itemLength); if (stream.readRawData(buffer.data(), itemLength) != itemLength) return false; chunkLength += itemLength + 2; if (itemType == CnameType) cname = QString::fromUtf8(buffer); else if (itemType == NameType) name = QString::fromUtf8(buffer); } return readPadding(stream, chunkLength); } void QXmppRtcpSourceDescriptionPrivate::write(QDataStream &stream) const { QByteArray buffer; quint16 chunkLength = 0; stream << ssrc; if (!cname.isEmpty()) { buffer = cname.toUtf8(); stream << quint8(CnameType); stream << quint8(buffer.size()); stream.writeRawData(buffer.constData(), buffer.size()); chunkLength += 2 + buffer.size(); } if (!name.isEmpty()) { buffer = name.toUtf8(); stream << quint8(NameType); stream << quint8(buffer.size()); stream.writeRawData(buffer.constData(), buffer.size()); chunkLength += 2 + buffer.size(); } stream << quint8(0); chunkLength++; writePadding(stream, chunkLength); } qxmpp-0.9.3/src/base/QXmppRtcpPacket.h000066400000000000000000000101021263006255200175630ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPRTCPPACKET_H #define QXMPPRTCPPACKET_H #include #include "QXmppGlobal.h" class QXmppRtcpPacketPrivate; class QXmppRtcpReceiverReport; class QXmppRtcpReceiverReportPrivate; class QXmppRtcpSenderInfo; class QXmppRtcpSenderInfoPrivate; class QXmppRtcpSourceDescription; class QXmppRtcpSourceDescriptionPrivate; /// \internal /// /// The QXmppRtcpPacket class represents an RTCP packet. class QXMPP_EXPORT QXmppRtcpPacket { public: enum Type { SenderReport = 200, ReceiverReport = 201, SourceDescription = 202, Goodbye = 203, }; QXmppRtcpPacket(); QXmppRtcpPacket(const QXmppRtcpPacket &other); ~QXmppRtcpPacket(); bool decode(const QByteArray &ba); QByteArray encode() const; bool read(QDataStream &stream); void write(QDataStream &stream) const; QString goodbyeReason() const; void setGoodbyeReason(const QString &goodbyeReason); QList goodbyeSsrcs() const; void setGoodbyeSsrcs(const QList &goodbyeSsrcs); QList receiverReports() const; void setReceiverReports(const QList &reports); QXmppRtcpSenderInfo senderInfo() const; void setSenderInfo(const QXmppRtcpSenderInfo &senderInfo); QList sourceDescriptions() const; void setSourceDescriptions(const QList &descriptions); quint32 ssrc() const; void setSsrc(quint32 ssrc); quint8 type() const; void setType(quint8 type); private: QSharedDataPointer d; }; /// \internal class QXMPP_EXPORT QXmppRtcpReceiverReport { public: QXmppRtcpReceiverReport(); QXmppRtcpReceiverReport(const QXmppRtcpReceiverReport &other); ~QXmppRtcpReceiverReport(); quint32 dlsr() const; void setDlsr(quint32 dlsr); quint8 fractionLost() const; void setFractionLost(quint8 fractionLost); quint32 jitter() const; void setJitter(quint32 jitter); quint32 lsr() const; void setLsr(quint32 lsr); quint32 ssrc() const; void setSsrc(quint32 ssrc); quint32 totalLost() const; void setTotalLost(quint32 totalLost); private: friend class QXmppRtcpPacket; QSharedDataPointer d; }; /// \internal class QXMPP_EXPORT QXmppRtcpSenderInfo { public: QXmppRtcpSenderInfo(); QXmppRtcpSenderInfo(const QXmppRtcpSenderInfo &other); ~QXmppRtcpSenderInfo(); quint64 ntpStamp() const; void setNtpStamp(quint64 ntpStamp); quint32 rtpStamp() const; void setRtpStamp(quint32 rtpStamp); quint32 octetCount() const; void setOctetCount(quint32 count); quint32 packetCount() const; void setPacketCount(quint32 count); private: friend class QXmppRtcpPacket; QSharedDataPointer d; }; /// \internal class QXMPP_EXPORT QXmppRtcpSourceDescription { public: QXmppRtcpSourceDescription(); QXmppRtcpSourceDescription(const QXmppRtcpSourceDescription &other); ~QXmppRtcpSourceDescription(); QString cname() const; void setCname(const QString &name); QString name() const; void setName(const QString &name); quint32 ssrc() const; void setSsrc(const quint32 ssrc); private: friend class QXmppRtcpPacket; QSharedDataPointer d; }; #endif qxmpp-0.9.3/src/base/QXmppRtpChannel.cpp000066400000000000000000000665421263006255200201370ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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_p.h" #include "QXmppJingleIq.h" #include "QXmppRtpChannel.h" #include "QXmppRtpPacket.h" #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288 #endif //#define QXMPP_DEBUG_RTP //#define QXMPP_DEBUG_RTP_BUFFER #define SAMPLE_BYTES 2 /// Creates a new RTP channel. QXmppRtpChannel::QXmppRtpChannel() : m_outgoingPayloadNumbered(false) { m_outgoingSsrc = qrand(); } /// 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(); } /// Returns the local SSRC. quint32 QXmppRtpChannel::localSsrc() const { return m_outgoingSsrc; } /// Sets the local SSRC. /// /// \param ssrc void QXmppRtpChannel::setLocalSsrc(quint32 ssrc) { m_outgoingSsrc = ssrc; } 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(); 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; QXmppJinglePayloadType payloadType; }; QXmppRtpAudioChannelPrivate::QXmppRtpAudioChannelPrivate() : signalsEmitted(false) , writtenSinceLastEmit(0) , incomingBuffering(true) , incomingMinimum(0) , incomingMaximum(0) , incomingPos(0) , incomingSequence(0) , outgoingCodec(0) , outgoingMarker(true) , outgoingPayloadNumbered(false) , outgoingSequence(1) , outgoingStamp(0) , outgoingTimer(0) { qRegisterMetaType("QXmppRtpAudioChannel::Tone"); } /// 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 #ifdef QXMPP_USE_OPUS else if (payloadType.name().toLower() == "opus") return new QXmppOpusCodec(payloadType.clockrate(), payloadType.channels()); #endif return 0; } /// Constructs a new RTP audio channel with the given \a parent. QXmppRtpAudioChannel::QXmppRtpAudioChannel(QObject *parent) : QIODevice(parent) , d(new QXmppRtpAudioChannelPrivate()) { 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_OPUS payload.setId(100); // NOTE: I don't know if this Id is ok for Opus. payload.setChannels(1); payload.setName("opus"); payload.setClockrate(8000); m_outgoingPayloadTypes << payload; #endif #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 QIODevice::bytesAvailable() + d->incomingBuffer.size(); } /// Closes the RTP audio 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; const quint8 packetType = packet.type(); if (!d->incomingCodecs.contains(packetType)) { foreach (const QXmppJinglePayloadType &payload, m_incomingPayloadTypes) { if (packetType == payload.id()) { codec = d->codecForPayloadType(payload); break; } } if (codec) d->incomingCodecs.insert(packetType, codec); else warning(QString("Could not find codec for RTP type %1").arg(QString::number(packetType))); } else { codec = d->incomingCodecs.value(packetType); } 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! const 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; } /// Returns the mode in which the channel has been opened. QIODevice::OpenMode QXmppRtpAudioChannel::openMode() const { return QIODevice::openMode(); } /// 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; } /// \cond 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; } 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); } /// \endcond /// 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; } } } /// \cond 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; } /// \endcond 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.setMarker(info.outgoingStart == d->outgoingStamp); packet.setType(d->outgoingTonesType.id()); packet.setSequence(d->outgoingSequence); packet.setStamp(info.outgoingStart); packet.setSsrc(localSsrc()); QByteArray payload; QDataStream output(&payload, QIODevice::WriteOnly); output << quint8(info.tone); output << quint8(info.finished ? 0x80 : 0x00); output << quint16(d->outgoingStamp + packetTicks - info.outgoingStart); packet.setPayload(payload); #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; if (d->outgoingMarker) { packet.setMarker(true); d->outgoingMarker = false; } else { packet.setMarker(false); } packet.setType(d->payloadType.id()); packet.setSequence(d->outgoingSequence); packet.setStamp(d->outgoingStamp); packet.setSsrc(localSsrc()); // encode audio chunk QDataStream input(chunk); input.setByteOrder(QDataStream::LittleEndian); QByteArray payload; QDataStream output(&payload, QIODevice::WriteOnly); const qint64 packetTicks = d->outgoingCodec->encode(input, output); packet.setPayload(payload); #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); } /// Returns a pointer to the start of the frame data buffer. uchar *QXmppVideoFrame::bits() { return (uchar*)m_data.data(); } /// Returns a pointer to the start of the frame data buffer. 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; }; QXmppRtpVideoChannelPrivate::QXmppRtpVideoChannelPrivate() : encoder(0), outgoingId(0), outgoingSequence(1), outgoingStamp(0) { } /// Constructs a new RTP video channel with the given \a parent. 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(256000); 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 video 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); } /// Returns the video format used by the encoder. QXmppVideoFormat QXmppRtpVideoChannel::decoderFormat() const { if (d->decoders.isEmpty()) return QXmppVideoFormat(); const int key = d->decoders.keys().first(); return d->decoders.value(key)->format(); } /// Returns the video format used by the encoder. QXmppVideoFormat QXmppRtpVideoChannel::encoderFormat() const { return d->outgoingFormat; } /// Sets the video format used by the encoder. void QXmppRtpVideoChannel::setEncoderFormat(const QXmppVideoFormat &format) { if (d->encoder && !d->encoder->setFormat(format)) return; d->outgoingFormat = format; } /// Returns the mode in which the channel has been opened. 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; } /// \cond 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(payload.clockrate()); } #endif if (encoder) { encoder->setFormat(d->outgoingFormat); d->encoder = encoder; d->outgoingId = payload.id(); break; } } } /// \endcond /// Decodes buffered RTP packets and returns a list of video frames. QList QXmppRtpVideoChannel::readFrames() { const QList frames = d->frames; d->frames.clear(); return frames; } /// Encodes a video \a frame and sends RTP packets. void QXmppRtpVideoChannel::writeFrame(const QXmppVideoFrame &frame) { if (!d->encoder) { warning("QXmppRtpVideoChannel::writeFrame before codec was set"); return; } QXmppRtpPacket packet; packet.setMarker(false); packet.setType(d->outgoingId); packet.setSsrc(localSsrc()); foreach (const QByteArray &payload, d->encoder->handleFrame(frame)) { packet.setSequence(d->outgoingSequence++); packet.setStamp(d->outgoingStamp); packet.setPayload(payload); #ifdef QXMPP_DEBUG_RTP logSent(packet.toString()); #endif emit sendDatagram(packet.encode()); } d->outgoingStamp += 1; } qxmpp-0.9.3/src/base/QXmppRtpChannel.h000066400000000000000000000207051263006255200175730ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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; class QXMPP_EXPORT QXmppRtpChannel { public: QXmppRtpChannel(); /// Closes the RTP channel. virtual void close() = 0; /// Returns the mode in which the channel has been opened. virtual QIODevice::OpenMode openMode() const = 0; QList localPayloadTypes(); void setRemotePayloadTypes(const QList &remotePayloadTypes); quint32 localSsrc() const; void setLocalSsrc(quint32 ssrc); protected: /// \cond virtual void payloadTypesChanged() = 0; QList m_incomingPayloadTypes; QList m_outgoingPayloadTypes; bool m_outgoingPayloadNumbered; /// \endcond private: quint32 m_outgoingSsrc; }; /// \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 QXMPP_EXPORT 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(); qint64 bytesAvailable() const; void close(); bool isSequential() const; QIODevice::OpenMode openMode() const; QXmppJinglePayloadType payloadType() const; qint64 pos() const; bool seek(qint64 pos); 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 QXMPP_EXPORT QXmppVideoFrame { public: /// This enum describes a pixel format. enum PixelFormat { Format_Invalid = 0, ///< The frame is invalid. Format_RGB32 = 3, ///< The frame stored using a 32-bit RGB format (0xffRRGGBB). Format_RGB24 = 4, ///< The frame is stored using a 24-bit RGB format (8-8-8). Format_YUV420P = 18, ///< The frame is stored using an 8-bit per component planar ///< YUV format with the U and V planes horizontally and ///< vertically sub-sampled, i.e. the height and width of the ///< U and V planes are half that of the Y plane. Format_UYVY = 20, ///< The frame is stored using an 8-bit per component packed ///< YUV format with the U and V planes horizontally ///< sub-sampled (U-Y-V-Y), i.e. two horizontally adjacent ///< pixels are stored as a 32-bit macropixel which has a Y ///< value for each pixel and common U and V values. Format_YUYV = 21 ///< The frame is stored using an 8-bit per component packed ///< YUV format with the U and V planes horizontally ///< sub-sampled (Y-U-Y-V), i.e. two horizontally adjacent ///< pixels are stored as a 32-bit macropixel which has a Y ///< value for each pixel and common U and V values. }; 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 QXMPP_EXPORT 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 QXMPP_EXPORT QXmppRtpVideoChannel : public QXmppLoggable, public QXmppRtpChannel { Q_OBJECT public: QXmppRtpVideoChannel(QObject *parent = 0); ~QXmppRtpVideoChannel(); void close(); QIODevice::OpenMode openMode() const; // incoming stream QXmppVideoFormat decoderFormat() const; QList readFrames(); // outgoing stream QXmppVideoFormat encoderFormat() const; void setEncoderFormat(const QXmppVideoFormat &format); void writeFrame(const QXmppVideoFrame &frame); 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: /// \cond void payloadTypesChanged(); /// \endcond private: friend class QXmppRtpVideoChannelPrivate; QXmppRtpVideoChannelPrivate * d; }; #endif qxmpp-0.9.3/src/base/QXmppRtpPacket.cpp000066400000000000000000000110231263006255200177560ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppRtpPacket.h" #define RTP_VERSION 2 class QXmppRtpPacketPrivate : public QSharedData { public: QXmppRtpPacketPrivate(); /// Marker flag. bool marker; /// Payload type. quint8 type; /// Synchronization source. quint32 ssrc; /// Contributing sources. QList csrc; /// Sequence number. quint16 sequence; /// Timestamp. quint32 stamp; /// Raw payload data. QByteArray payload; }; QXmppRtpPacketPrivate::QXmppRtpPacketPrivate() : marker(false) , type(0) , ssrc(0) , sequence(0) , stamp(0) { } /// Constructs an empty RTP packet QXmppRtpPacket::QXmppRtpPacket() : d(new QXmppRtpPacketPrivate()) { } /// Constructs a copy of other. /// /// \param other /// QXmppRtpPacket::QXmppRtpPacket(const QXmppRtpPacket &other) : d(other.d) { } QXmppRtpPacket::~QXmppRtpPacket() { } /// Assigns the other packet to this one. /// /// \param other /// QXmppRtpPacket& QXmppRtpPacket::operator=(const QXmppRtpPacket& other) { d = other.d; return *this; } /// 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; const quint8 cc = (tmp >> 1) & 0xf; const int hlen = 12 + 4 * cc; if ((tmp >> 6) != RTP_VERSION || ba.size() < hlen) return false; stream >> tmp; d->marker = (tmp >> 7); d->type = tmp & 0x7f; stream >> d->sequence; stream >> d->stamp; stream >> d->ssrc; // contributing source IDs d->csrc.clear(); quint32 src; for (int i = 0; i < cc; ++i) { stream >> src; d->csrc << src; } // retrieve payload d->payload = ba.right(ba.size() - hlen); return true; } /// Encodes an RTP packet. QByteArray QXmppRtpPacket::encode() const { Q_ASSERT(d->csrc.size() < 16); // fixed header QByteArray ba; ba.resize(d->payload.size() + 12 + 4 * d->csrc.size()); QDataStream stream(&ba, QIODevice::WriteOnly); stream << quint8((RTP_VERSION << 6) | ((d->csrc.size() & 0xf) << 1)); stream << quint8((d->type & 0x7f) | (d->marker << 7)); stream << d->sequence; stream << d->stamp; stream << d->ssrc; // contributing source ids foreach (const quint32 &src, d->csrc) stream << src; stream.writeRawData(d->payload.constData(), d->payload.size()); return ba; } QList QXmppRtpPacket::csrc() const { return d->csrc; } void QXmppRtpPacket::setCsrc(const QList &csrc) { d->csrc = csrc; } bool QXmppRtpPacket::marker() const { return d->marker; } void QXmppRtpPacket::setMarker(bool marker) { d->marker = marker; } QByteArray QXmppRtpPacket::payload() const { return d->payload; } void QXmppRtpPacket::setPayload(const QByteArray &payload) { d->payload = payload; } quint32 QXmppRtpPacket::ssrc() const { return d->ssrc; } void QXmppRtpPacket::setSsrc(quint32 ssrc) { d->ssrc = ssrc; } quint16 QXmppRtpPacket::sequence() const { return d->sequence; } void QXmppRtpPacket::setSequence(quint16 sequence) { d->sequence = sequence; } quint32 QXmppRtpPacket::stamp() const { return d->stamp; } void QXmppRtpPacket::setStamp(quint32 stamp) { d->stamp = stamp; } quint8 QXmppRtpPacket::type() const { return d->type; } void QXmppRtpPacket::setType(quint8 type) { d->type = type; } /// 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(d->sequence), QString::number(d->stamp), QString::number(d->marker), QString::number(d->type), QString::number(d->payload.size())); } qxmpp-0.9.3/src/base/QXmppRtpPacket.h000066400000000000000000000033471263006255200174350ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPRTPPACKET_H #define QXMPPRTPPACKET_H #include #include "QXmppGlobal.h" class QXmppRtpPacketPrivate; /// \internal /// /// The QXmppRtpPacket class represents an RTP packet. class QXMPP_EXPORT QXmppRtpPacket { public: QXmppRtpPacket(); QXmppRtpPacket(const QXmppRtpPacket &other); ~QXmppRtpPacket(); QXmppRtpPacket& operator=(const QXmppRtpPacket &other); bool decode(const QByteArray &ba); QByteArray encode() const; QString toString() const; QList csrc() const; void setCsrc(const QList &csrc); bool marker() const; void setMarker(bool marker); QByteArray payload() const; void setPayload(const QByteArray &payload); quint16 sequence() const; void setSequence(quint16 sequence); quint32 ssrc() const; void setSsrc(quint32 ssrc); quint32 stamp() const; void setStamp(quint32 stamp); quint8 type() const; void setType(quint8 type); private: QSharedDataPointer d; }; #endif qxmpp-0.9.3/src/base/QXmppSasl.cpp000066400000000000000000000517521263006255200170000ustar00rootroot00000000000000/* * Copyright (C) 2008-2013 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 #if QT_VERSION >= 0x050000 #include #else #include #endif #include "QXmppSasl_p.h" #include "QXmppUtils.h" const char *ns_xmpp_sasl = "urn:ietf:params:xml:ns:xmpp-sasl"; static QByteArray forcedNonce; // Calculate digest response for use with XMPP/SASL. static QByteArray calculateDigest(const QByteArray &method, const QByteArray &digestUri, const QByteArray &secret, const QByteArray &nonce, const QByteArray &cnonce, const QByteArray &nc) { const QByteArray A1 = secret + ':' + nonce + ':' + cnonce; const QByteArray A2 = method + ':' + digestUri; QByteArray HA1 = QCryptographicHash::hash(A1, QCryptographicHash::Md5).toHex(); QByteArray HA2 = QCryptographicHash::hash(A2, QCryptographicHash::Md5).toHex(); const QByteArray KD = HA1 + ':' + nonce + ':' + nc + ':' + cnonce + ":auth:" + HA2; return QCryptographicHash::hash(KD, QCryptographicHash::Md5).toHex(); } static QByteArray generateNonce() { if (!forcedNonce.isEmpty()) return forcedNonce; QByteArray nonce = QXmppUtils::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(); } QXmppSaslAuth::QXmppSaslAuth(const QString &mechanism, const QByteArray &value) : m_mechanism(mechanism) , m_value(value) { } QString QXmppSaslAuth::mechanism() const { return m_mechanism; } void QXmppSaslAuth::setMechanism(const QString &mechanism) { m_mechanism = mechanism; } QByteArray QXmppSaslAuth::value() const { return m_value; } void QXmppSaslAuth::setValue(const QByteArray &value) { m_value = value; } void QXmppSaslAuth::parse(const QDomElement &element) { m_mechanism = element.attribute("mechanism"); m_value = QByteArray::fromBase64(element.text().toLatin1()); } void QXmppSaslAuth::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement("auth"); writer->writeAttribute("xmlns", ns_xmpp_sasl); writer->writeAttribute("mechanism", m_mechanism); if (!m_value.isEmpty()) writer->writeCharacters(m_value.toBase64()); writer->writeEndElement(); } QXmppSaslChallenge::QXmppSaslChallenge(const QByteArray &value) : m_value(value) { } QByteArray QXmppSaslChallenge::value() const { return m_value; } void QXmppSaslChallenge::setValue(const QByteArray &value) { m_value = value; } void QXmppSaslChallenge::parse(const QDomElement &element) { m_value = QByteArray::fromBase64(element.text().toLatin1()); } void QXmppSaslChallenge::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement("challenge"); writer->writeAttribute("xmlns", ns_xmpp_sasl); if (!m_value.isEmpty()) writer->writeCharacters(m_value.toBase64()); writer->writeEndElement(); } QXmppSaslFailure::QXmppSaslFailure(const QString &condition) : m_condition(condition) { } QString QXmppSaslFailure::condition() const { return m_condition; } void QXmppSaslFailure::setCondition(const QString &condition) { m_condition = condition; } void QXmppSaslFailure::parse(const QDomElement &element) { m_condition = element.firstChildElement().tagName(); } void QXmppSaslFailure::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement("failure"); writer->writeAttribute("xmlns", ns_xmpp_sasl); if (!m_condition.isEmpty()) writer->writeEmptyElement(m_condition); writer->writeEndElement(); } QXmppSaslResponse::QXmppSaslResponse(const QByteArray &value) : m_value(value) { } QByteArray QXmppSaslResponse::value() const { return m_value; } void QXmppSaslResponse::setValue(const QByteArray &value) { m_value = value; } void QXmppSaslResponse::parse(const QDomElement &element) { m_value = QByteArray::fromBase64(element.text().toLatin1()); } void QXmppSaslResponse::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement("response"); writer->writeAttribute("xmlns", ns_xmpp_sasl); if (!m_value.isEmpty()) writer->writeCharacters(m_value.toBase64()); writer->writeEndElement(); } QXmppSaslSuccess::QXmppSaslSuccess() { } void QXmppSaslSuccess::parse(const QDomElement &element) { Q_UNUSED(element); } void QXmppSaslSuccess::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement("success"); writer->writeAttribute("xmlns", ns_xmpp_sasl); writer->writeEndElement(); } class QXmppSaslClientPrivate { public: QString host; QString serviceType; QString username; QString password; }; QXmppSaslClient::QXmppSaslClient(QObject *parent) : QXmppLoggable(parent) , d(new QXmppSaslClientPrivate) { } QXmppSaslClient::~QXmppSaslClient() { delete d; } /// Returns a list of supported mechanisms. QStringList QXmppSaslClient::availableMechanisms() { return QStringList() << "PLAIN" << "DIGEST-MD5" << "ANONYMOUS" << "X-FACEBOOK-PLATFORM" << "X-MESSENGER-OAUTH2" << "X-OAUTH2"; } /// Creates an SASL client for the given mechanism. QXmppSaslClient* QXmppSaslClient::create(const QString &mechanism, QObject *parent) { if (mechanism == "PLAIN") { return new QXmppSaslClientPlain(parent); } else if (mechanism == "DIGEST-MD5") { return new QXmppSaslClientDigestMd5(parent); } else if (mechanism == "ANONYMOUS") { return new QXmppSaslClientAnonymous(parent); } else if (mechanism == "X-FACEBOOK-PLATFORM") { return new QXmppSaslClientFacebook(parent); } else if (mechanism == "X-MESSENGER-OAUTH2") { return new QXmppSaslClientWindowsLive(parent); } else if (mechanism == "X-OAUTH2") { return new QXmppSaslClientGoogle(parent); } else { return 0; } } /// Returns the host. QString QXmppSaslClient::host() const { return d->host; } /// Sets the host. void QXmppSaslClient::setHost(const QString &host) { d->host = host; } /// Returns the service type, e.g. "xmpp". QString QXmppSaslClient::serviceType() const { return d->serviceType; } /// Sets the service type, e.g. "xmpp". void QXmppSaslClient::setServiceType(const QString &serviceType) { d->serviceType = serviceType; } /// Returns the username. QString QXmppSaslClient::username() const { return d->username; } /// Sets the username. void QXmppSaslClient::setUsername(const QString &username) { d->username = username; } /// Returns the password. QString QXmppSaslClient::password() const { return d->password; } /// Sets the password. void QXmppSaslClient::setPassword(const QString &password) { d->password = password; } QXmppSaslClientAnonymous::QXmppSaslClientAnonymous(QObject *parent) : QXmppSaslClient(parent) , m_step(0) { } QString QXmppSaslClientAnonymous::mechanism() const { return "ANONYMOUS"; } bool QXmppSaslClientAnonymous::respond(const QByteArray &challenge, QByteArray &response) { Q_UNUSED(challenge); if (m_step == 0) { response = QByteArray(); m_step++; return true; } else { warning("QXmppSaslClientAnonymous : Invalid step"); return false; } } QXmppSaslClientDigestMd5::QXmppSaslClientDigestMd5(QObject *parent) : QXmppSaslClient(parent) , m_nc("00000001") , m_step(0) { m_cnonce = generateNonce(); } QString QXmppSaslClientDigestMd5::mechanism() const { return "DIGEST-MD5"; } bool QXmppSaslClientDigestMd5::respond(const QByteArray &challenge, QByteArray &response) { Q_UNUSED(challenge); const QByteArray digestUri = QString("%1/%2").arg(serviceType(), host()).toUtf8(); if (m_step == 0) { response = QByteArray(); m_step++; return true; } else if (m_step == 1) { const QMap input = QXmppSaslDigestMd5::parseMessage(challenge); if (!input.contains("nonce")) { warning("QXmppSaslClientDigestMd5 : Invalid input on step 1"); return false; } // determine realm const QByteArray realm = input.value("realm"); // determine quality of protection const QList qops = input.value("qop", "auth").split(','); if (!qops.contains("auth")) { warning("QXmppSaslClientDigestMd5 : Invalid quality of protection"); return false; } m_nonce = input.value("nonce"); m_secret = QCryptographicHash::hash( username().toUtf8() + ":" + realm + ":" + password().toUtf8(), QCryptographicHash::Md5); // Build response QMap output; output["username"] = username().toUtf8(); if (!realm.isEmpty()) output["realm"] = realm; output["nonce"] = m_nonce; output["qop"] = "auth"; output["cnonce"] = m_cnonce; output["nc"] = m_nc; output["digest-uri"] = digestUri; output["response"] = calculateDigest("AUTHENTICATE", digestUri, m_secret, m_nonce, m_cnonce, m_nc); output["charset"] = "utf-8"; response = QXmppSaslDigestMd5::serializeMessage(output); m_step++; return true; } else if (m_step == 2) { const QMap input = QXmppSaslDigestMd5::parseMessage(challenge); // check new challenge if (input.value("rspauth") != calculateDigest(QByteArray(), digestUri, m_secret, m_nonce, m_cnonce, m_nc)) { warning("QXmppSaslClientDigestMd5 : Invalid challenge on step 2"); return false; } response = QByteArray(); m_step++; return true; } else { warning("QXmppSaslClientDigestMd5 : Invalid step"); return false; } } QXmppSaslClientFacebook::QXmppSaslClientFacebook(QObject *parent) : QXmppSaslClient(parent) , m_step(0) { } QString QXmppSaslClientFacebook::mechanism() const { return "X-FACEBOOK-PLATFORM"; } bool QXmppSaslClientFacebook::respond(const QByteArray &challenge, QByteArray &response) { if (m_step == 0) { // no initial response response = QByteArray(); m_step++; return true; } else if (m_step == 1) { // parse request #if QT_VERSION >= 0x050000 QUrlQuery requestUrl(challenge); #else QUrl requestUrl; requestUrl.setEncodedQuery(challenge); #endif if (!requestUrl.hasQueryItem("method") || !requestUrl.hasQueryItem("nonce")) { warning("QXmppSaslClientFacebook : Invalid challenge, nonce or method missing"); return false; } // build response #if QT_VERSION >= 0x050000 QUrlQuery responseUrl; #else QUrl responseUrl; #endif responseUrl.addQueryItem("access_token", password()); responseUrl.addQueryItem("api_key", username()); responseUrl.addQueryItem("call_id", 0); responseUrl.addQueryItem("method", requestUrl.queryItemValue("method")); responseUrl.addQueryItem("nonce", requestUrl.queryItemValue("nonce")); responseUrl.addQueryItem("v", "1.0"); #if QT_VERSION >= 0x050000 response = responseUrl.query().toUtf8(); #else response = responseUrl.encodedQuery(); #endif m_step++; return true; } else { warning("QXmppSaslClientFacebook : Invalid step"); return false; } } QXmppSaslClientGoogle::QXmppSaslClientGoogle(QObject *parent) : QXmppSaslClient(parent) , m_step(0) { } QString QXmppSaslClientGoogle::mechanism() const { return "X-OAUTH2"; } bool QXmppSaslClientGoogle::respond(const QByteArray &challenge, QByteArray &response) { Q_UNUSED(challenge); if (m_step == 0) { // send initial response response = QString('\0' + username() + '\0' + password()).toUtf8(); m_step++; return true; } else { warning("QXmppSaslClientGoogle : Invalid step"); return false; } } QXmppSaslClientPlain::QXmppSaslClientPlain(QObject *parent) : QXmppSaslClient(parent) , m_step(0) { } QString QXmppSaslClientPlain::mechanism() const { return "PLAIN"; } bool QXmppSaslClientPlain::respond(const QByteArray &challenge, QByteArray &response) { Q_UNUSED(challenge); if (m_step == 0) { response = QString('\0' + username() + '\0' + password()).toUtf8(); m_step++; return true; } else { warning("QXmppSaslClientPlain : Invalid step"); return false; } } QXmppSaslClientWindowsLive::QXmppSaslClientWindowsLive(QObject *parent) : QXmppSaslClient(parent) , m_step(0) { } QString QXmppSaslClientWindowsLive::mechanism() const { return "X-MESSENGER-OAUTH2"; } bool QXmppSaslClientWindowsLive::respond(const QByteArray &challenge, QByteArray &response) { Q_UNUSED(challenge); if (m_step == 0) { // send initial response response = QByteArray::fromBase64(password().toLatin1()); m_step++; return true; } else { warning("QXmppSaslClientWindowsLive : Invalid step"); return false; } } class QXmppSaslServerPrivate { public: QString username; QString password; QByteArray passwordDigest; QString realm; }; QXmppSaslServer::QXmppSaslServer(QObject *parent) : QXmppLoggable(parent) , d(new QXmppSaslServerPrivate) { } QXmppSaslServer::~QXmppSaslServer() { delete d; } /// Creates an SASL server for the given mechanism. QXmppSaslServer* QXmppSaslServer::create(const QString &mechanism, QObject *parent) { if (mechanism == "PLAIN") { return new QXmppSaslServerPlain(parent); } else if (mechanism == "DIGEST-MD5") { return new QXmppSaslServerDigestMd5(parent); } else if (mechanism == "ANONYMOUS") { return new QXmppSaslServerAnonymous(parent); } else { return 0; } } /// Returns the username. QString QXmppSaslServer::username() const { return d->username; } /// Sets the username. void QXmppSaslServer::setUsername(const QString &username) { d->username = username; } /// Returns the password. QString QXmppSaslServer::password() const { return d->password; } /// Sets the password. void QXmppSaslServer::setPassword(const QString &password) { d->password = password; } /// Returns the password digest. QByteArray QXmppSaslServer::passwordDigest() const { return d->passwordDigest; } /// Sets the password digest. void QXmppSaslServer::setPasswordDigest(const QByteArray &digest) { d->passwordDigest = digest; } /// Returns the realm. QString QXmppSaslServer::realm() const { return d->realm; } /// Sets the realm. void QXmppSaslServer::setRealm(const QString &realm) { d->realm = realm; } QXmppSaslServerAnonymous::QXmppSaslServerAnonymous(QObject *parent) : QXmppSaslServer(parent) , m_step(0) { } QString QXmppSaslServerAnonymous::mechanism() const { return "ANONYMOUS"; } QXmppSaslServer::Response QXmppSaslServerAnonymous::respond(const QByteArray &request, QByteArray &response) { Q_UNUSED(request); if (m_step == 0) { m_step++; response = QByteArray(); return Succeeded; } else { warning("QXmppSaslServerAnonymous : Invalid step"); return Failed; } } QXmppSaslServerDigestMd5::QXmppSaslServerDigestMd5(QObject *parent) : QXmppSaslServer(parent) , m_step(0) { m_nonce = generateNonce(); } QString QXmppSaslServerDigestMd5::mechanism() const { return "DIGEST-MD5"; } QXmppSaslServer::Response QXmppSaslServerDigestMd5::respond(const QByteArray &request, QByteArray &response) { if (m_step == 0) { QMap output; output["nonce"] = m_nonce; if (!realm().isEmpty()) output["realm"] = realm().toUtf8(); output["qop"] = "auth"; output["charset"] = "utf-8"; output["algorithm"] = "md5-sess"; m_step++; response = QXmppSaslDigestMd5::serializeMessage(output); return Challenge; } else if (m_step == 1) { const QMap input = QXmppSaslDigestMd5::parseMessage(request); const QByteArray realm = input.value("realm"); const QByteArray digestUri = input.value("digest-uri"); if (input.value("qop") != "auth") { warning("QXmppSaslServerDigestMd5 : Invalid quality of protection"); return Failed; } setUsername(QString::fromUtf8(input.value("username"))); if (password().isEmpty() && passwordDigest().isEmpty()) return InputNeeded; m_nc = input.value("nc"); m_cnonce = input.value("cnonce"); if (!password().isEmpty()) { m_secret = QCryptographicHash::hash( username().toUtf8() + ":" + realm + ":" + password().toUtf8(), QCryptographicHash::Md5); } else { m_secret = passwordDigest(); } if (input.value("response") != calculateDigest("AUTHENTICATE", digestUri, m_secret, m_nonce, m_cnonce, m_nc)) return Failed; QMap output; output["rspauth"] = calculateDigest(QByteArray(), digestUri, m_secret, m_nonce, m_cnonce, m_nc); m_step++; response = QXmppSaslDigestMd5::serializeMessage(output); return Challenge; } else if (m_step == 2) { m_step++; response = QByteArray(); return Succeeded; } else { warning("QXmppSaslServerDigestMd5 : Invalid step"); return Failed; } } QXmppSaslServerPlain::QXmppSaslServerPlain(QObject *parent) : QXmppSaslServer(parent) , m_step(0) { } QString QXmppSaslServerPlain::mechanism() const { return "PLAIN"; } QXmppSaslServer::Response QXmppSaslServerPlain::respond(const QByteArray &request, QByteArray &response) { if (m_step == 0) { if (request.isEmpty()) { response = QByteArray(); return Challenge; } QList auth = request.split('\0'); if (auth.size() != 3) { warning("QXmppSaslServerPlain : Invalid input"); return Failed; } setUsername(QString::fromUtf8(auth[1])); setPassword(QString::fromUtf8(auth[2])); m_step++; response = QByteArray(); return InputNeeded; } else { warning("QXmppSaslServerPlain : Invalid step"); return Failed; } } void QXmppSaslDigestMd5::setNonce(const QByteArray &nonce) { forcedNonce = nonce; } 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; } qxmpp-0.9.3/src/base/QXmppSasl_p.h000066400000000000000000000170361263006255200167610ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPSASL_P_H #define QXMPPSASL_P_H #include #include #include "QXmppGlobal.h" #include "QXmppLogger.h" #include "QXmppStanza.h" class QXmppSaslClientPrivate; class QXmppSaslServerPrivate; // // W A R N I N G // ------------- // // This file is not part of the QXmpp API. It exists for the convenience // of the QXmppIncomingClient and QXmppOutgoingClient classes. // // This header file may change from version to version without notice, // or even be removed. // // We mean it. // class QXMPP_AUTOTEST_EXPORT QXmppSaslClient : public QXmppLoggable { public: QXmppSaslClient(QObject *parent = 0); virtual ~QXmppSaslClient(); QString host() const; void setHost(const QString &host); QString serviceType() const; void setServiceType(const QString &serviceType); QString username() const; void setUsername(const QString &username); QString password() const; void setPassword(const QString &password); virtual QString mechanism() const = 0; virtual bool respond(const QByteArray &challenge, QByteArray &response) = 0; static QStringList availableMechanisms(); static QXmppSaslClient* create(const QString &mechanism, QObject *parent = 0); private: QXmppSaslClientPrivate *d; }; class QXMPP_AUTOTEST_EXPORT QXmppSaslServer : public QXmppLoggable { public: enum Response { Challenge = 0, Succeeded = 1, Failed = 2, InputNeeded = 3 }; QXmppSaslServer(QObject *parent = 0); virtual ~QXmppSaslServer(); QString username() const; void setUsername(const QString &username); QString password() const; void setPassword(const QString &password); QByteArray passwordDigest() const; void setPasswordDigest(const QByteArray &digest); QString realm() const; void setRealm(const QString &realm); virtual QString mechanism() const = 0; virtual Response respond(const QByteArray &challenge, QByteArray &response) = 0; static QXmppSaslServer* create(const QString &mechanism, QObject *parent = 0); private: QXmppSaslServerPrivate *d; }; class QXMPP_AUTOTEST_EXPORT QXmppSaslDigestMd5 { public: static void setNonce(const QByteArray &nonce); // message parsing and serialization static QMap parseMessage(const QByteArray &ba); static QByteArray serializeMessage(const QMap &map); }; class QXMPP_AUTOTEST_EXPORT QXmppSaslAuth : public QXmppStanza { public: QXmppSaslAuth(const QString &mechanism = QString(), const QByteArray &value = QByteArray()); QString mechanism() const; void setMechanism(const QString &mechanism); QByteArray value() const; void setValue(const QByteArray &value); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; /// \endcond private: QString m_mechanism; QByteArray m_value; }; class QXMPP_AUTOTEST_EXPORT QXmppSaslChallenge : public QXmppStanza { public: QXmppSaslChallenge(const QByteArray &value = QByteArray()); QByteArray value() const; void setValue(const QByteArray &value); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; /// \endcond private: QByteArray m_value; }; class QXMPP_AUTOTEST_EXPORT QXmppSaslFailure : public QXmppStanza { public: QXmppSaslFailure(const QString &condition = QString()); QString condition() const; void setCondition(const QString &condition); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; /// \endcond private: QString m_condition; }; class QXMPP_AUTOTEST_EXPORT QXmppSaslResponse : public QXmppStanza { public: QXmppSaslResponse(const QByteArray &value = QByteArray()); QByteArray value() const; void setValue(const QByteArray &value); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; /// \endcond private: QByteArray m_value; }; class QXMPP_AUTOTEST_EXPORT QXmppSaslSuccess : public QXmppStanza { public: QXmppSaslSuccess(); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; /// \endcond }; class QXmppSaslClientAnonymous : public QXmppSaslClient { public: QXmppSaslClientAnonymous(QObject *parent = 0); QString mechanism() const; bool respond(const QByteArray &challenge, QByteArray &response); private: int m_step; }; class QXmppSaslClientDigestMd5 : public QXmppSaslClient { public: QXmppSaslClientDigestMd5(QObject *parent = 0); QString mechanism() const; bool respond(const QByteArray &challenge, QByteArray &response); private: QByteArray m_cnonce; QByteArray m_nc; QByteArray m_nonce; QByteArray m_secret; int m_step; }; class QXmppSaslClientFacebook : public QXmppSaslClient { public: QXmppSaslClientFacebook(QObject *parent = 0); QString mechanism() const; bool respond(const QByteArray &challenge, QByteArray &response); private: int m_step; }; class QXmppSaslClientGoogle : public QXmppSaslClient { public: QXmppSaslClientGoogle(QObject *parent = 0); QString mechanism() const; bool respond(const QByteArray &challenge, QByteArray &response); private: int m_step; }; class QXmppSaslClientPlain : public QXmppSaslClient { public: QXmppSaslClientPlain(QObject *parent = 0); QString mechanism() const; bool respond(const QByteArray &challenge, QByteArray &response); private: int m_step; }; class QXmppSaslClientWindowsLive : public QXmppSaslClient { public: QXmppSaslClientWindowsLive(QObject *parent = 0); QString mechanism() const; bool respond(const QByteArray &challenge, QByteArray &response); private: int m_step; }; class QXmppSaslServerAnonymous : public QXmppSaslServer { public: QXmppSaslServerAnonymous(QObject *parent = 0); QString mechanism() const; Response respond(const QByteArray &challenge, QByteArray &response); private: int m_step; }; class QXmppSaslServerDigestMd5 : public QXmppSaslServer { public: QXmppSaslServerDigestMd5(QObject *parent = 0); QString mechanism() const; Response respond(const QByteArray &challenge, QByteArray &response); private: QByteArray m_cnonce; QByteArray m_nc; QByteArray m_nonce; QByteArray m_secret; int m_step; }; class QXmppSaslServerFacebook : public QXmppSaslServer { public: QXmppSaslServerFacebook(QObject *parent = 0); QString mechanism() const; Response respond(const QByteArray &challenge, QByteArray &response); private: int m_step; }; class QXmppSaslServerPlain : public QXmppSaslServer { public: QXmppSaslServerPlain(QObject *parent = 0); QString mechanism() const; Response respond(const QByteArray &challenge, QByteArray &response); private: int m_step; }; #endif qxmpp-0.9.3/src/base/QXmppSessionIq.cpp000066400000000000000000000024051263006255200200020ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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" /// \cond 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppSessionIq.h000066400000000000000000000023121263006255200174440ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 3921. /// /// \ingroup Stanzas class QXMPP_EXPORT QXmppSessionIq : public QXmppIq { public: /// \cond static bool isSessionIq(const QDomElement &element); /// \endcond private: /// \cond void toXmlElementFromChild(QXmlStreamWriter *writer) const; /// \endcond }; #endif // QXMPPSESSION_H qxmpp-0.9.3/src/base/QXmppSocks.cpp000066400000000000000000000214061263006255200171510ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppSocks.h" const static char SocksVersion = 5; enum AuthenticationMethod { NoAuthentication = 0, NoAcceptableMethod = 255 }; 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(QDataStream &stream, quint8 &type, QByteArray &host, quint16 &port) { // get host name quint8 hostLength; stream >> type; stream >> hostLength; if (stream.status() != QDataStream::Ok) return false; host.resize(hostLength); if (stream.readRawData(host.data(), hostLength) != hostLength) { qWarning("Invalid host length"); return false; } // get port stream >> port; return stream.status() == QDataStream::Ok; } QXmppSocksClient::QXmppSocksClient(const QString &proxyHost, quint16 proxyPort, QObject *parent) : QTcpSocket(parent), m_proxyHost(proxyHost), 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_proxyHost, 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) { // 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; } // advance state m_step = CommandState; // send CONNECT command buffer.resize(3); buffer[0] = SocksVersion; buffer[1] = ConnectCommand; buffer[2] = 0x00; // reserved buffer.append(encodeHostAndPort( DomainName, m_hostName.toLatin1(), m_hostPort)); write(buffer); } else if (m_step == CommandState) { // disconnect from signal disconnect(this, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); // receive CONNECT response QByteArray buffer = read(3); if (buffer.size() != 3 || 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; QDataStream stream(this); if (!parseHostAndPort(stream, 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 m_step = ReadyState; emit ready(); } } QXmppSocksServer::QXmppSocksServer(QObject *parent) : QObject(parent) { m_server = new QTcpServer(this); connect(m_server, SIGNAL(newConnection()), this, SLOT(slotNewConnection())); m_server_v6 = new QTcpServer(this); connect(m_server_v6, SIGNAL(newConnection()), this, SLOT(slotNewConnection())); } void QXmppSocksServer::close() { m_server->close(); m_server_v6->close(); } bool QXmppSocksServer::listen(quint16 port) { if (!m_server->listen(QHostAddress::Any, port)) return false; // FIXME: this fails on Linux if /proc/sys/net/ipv6/bindv6only is 0 m_server_v6->listen(QHostAddress::AnyIPv6, m_server->serverPort()); return true; } quint16 QXmppSocksServer::serverPort() const { return m_server->serverPort(); } void QXmppSocksServer::slotNewConnection() { QTcpServer *server = qobject_cast(sender()); if (!server) return; QTcpSocket *socket = 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) { // 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"); buffer.resize(2); buffer[0] = SocksVersion; buffer[1] = NoAcceptableMethod; socket->write(buffer); socket->close(); return; } // advance state m_states.insert(socket, CommandState); // send connect to server response buffer.resize(2); buffer[0] = SocksVersion; buffer[1] = NoAuthentication; socket->write(buffer); } else if (m_states.value(socket) == CommandState) { // disconnect from signals disconnect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); // receive command QByteArray buffer = socket->read(3); if (buffer.size() != 3 || 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; QDataStream stream(socket); if (!parseHostAndPort(stream, hostType, hostName, hostPort)) { qWarning("QXmppSocksServer could not parse type/host/port"); socket->close(); return; } // notify of connection m_states.insert(socket, ReadyState); 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); } } qxmpp-0.9.3/src/base/QXmppSocks.h000066400000000000000000000033631263006255200166200ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 #include "QXmppGlobal.h" class QTcpServer; class QXMPP_EXPORT QXmppSocksClient : public QTcpSocket { Q_OBJECT public: QXmppSocksClient(const QString &proxyHost, quint16 proxyPort, QObject *parent=0); void connectToHost(const QString &hostName, quint16 hostPort); signals: void ready(); private slots: void slotConnected(); void slotReadyRead(); private: QString m_proxyHost; quint16 m_proxyPort; QString m_hostName; quint16 m_hostPort; int m_step; }; class QXMPP_EXPORT QXmppSocksServer : public QObject { Q_OBJECT public: QXmppSocksServer(QObject *parent=0); void close(); bool listen(quint16 port = 0); quint16 serverPort() const; signals: void newConnection(QTcpSocket *socket, QString hostName, quint16 port); private slots: void slotNewConnection(); void slotReadyRead(); private: QTcpServer *m_server; QTcpServer *m_server_v6; QMap m_states; }; #endif qxmpp-0.9.3/src/base/QXmppStanza.cpp000066400000000000000000000342471263006255200173360ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * Georg Rudoy * * Source: * https://github.com/qxmpp-project/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; class QXmppExtendedAddressPrivate : public QSharedData { public: bool delivered; QString description; QString jid; QString type; }; /// Constructs an empty extended address. QXmppExtendedAddress::QXmppExtendedAddress() : d(new QXmppExtendedAddressPrivate()) { d->delivered = false; } /// Constructs a copy of other. /// /// \param other /// QXmppExtendedAddress::QXmppExtendedAddress(const QXmppExtendedAddress &other) : d(other.d) { } QXmppExtendedAddress::~QXmppExtendedAddress() { } /// Assigns the other address to this one. /// /// \param other /// QXmppExtendedAddress& QXmppExtendedAddress::operator=(const QXmppExtendedAddress& other) { d = other.d; return *this; } /// Returns the human-readable description of the address. QString QXmppExtendedAddress::description() const { return d->description; } /// Sets the human-readable \a description of the address. void QXmppExtendedAddress::setDescription(const QString &description) { d->description = description; } /// Returns the JID of the address. QString QXmppExtendedAddress::jid() const { return d->jid; } /// Sets the JID of the address. void QXmppExtendedAddress::setJid(const QString &jid) { d->jid = jid; } /// Returns the type of the address. QString QXmppExtendedAddress::type() const { return d->type; } /// Sets the \a type of the address. void QXmppExtendedAddress::setType(const QString &type) { d->type = type; } /// Returns whether the stanza has been delivered to this address. bool QXmppExtendedAddress::isDelivered() const { return d->delivered; } /// Sets whether the stanza has been \a delivered to this address. void QXmppExtendedAddress::setDelivered(bool delivered) { d->delivered = delivered; } /// Checks whether this address is valid. The extended address is considered /// to be valid if at least type and JID fields are non-empty. bool QXmppExtendedAddress::isValid() const { return !d->type.isEmpty() && !d->jid.isEmpty(); } /// \cond void QXmppExtendedAddress::parse(const QDomElement &element) { d->delivered = element.attribute("delivered") == "true"; d->description = element.attribute("desc"); d->jid = element.attribute("jid"); d->type = element.attribute("type"); } void QXmppExtendedAddress::toXml(QXmlStreamWriter *xmlWriter) const { xmlWriter->writeStartElement("address"); if (d->delivered) xmlWriter->writeAttribute("delivered", "true"); if (!d->description.isEmpty()) xmlWriter->writeAttribute("desc", d->description); xmlWriter->writeAttribute("jid", d->jid); xmlWriter->writeAttribute("type", d->type); xmlWriter->writeEndElement(); } /// \endcond 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; } /// \cond 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)); } 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(); } /// \endcond class QXmppStanzaPrivate : public QSharedData { public: QString to; QString from; QString id; QString lang; QXmppStanza::Error error; QXmppElementList extensions; QList extendedAddresses; }; /// Constructs a QXmppStanza with the specified sender and recipient. /// /// \param from /// \param to QXmppStanza::QXmppStanza(const QString& from, const QString& to) : d(new QXmppStanzaPrivate) { d->to = to; d->from = from; } /// Constructs a copy of \a other. QXmppStanza::QXmppStanza(const QXmppStanza &other) : d(other.d) { } /// Destroys a QXmppStanza. QXmppStanza::~QXmppStanza() { } /// Assigns \a other to this stanza. QXmppStanza& QXmppStanza::operator=(const QXmppStanza &other) { d = other.d; return *this; } /// Returns the stanza's recipient JID. /// QString QXmppStanza::to() const { return d->to; } /// Sets the stanza's recipient JID. /// /// \param to void QXmppStanza::setTo(const QString& to) { d->to = to; } /// Returns the stanza's sender JID. QString QXmppStanza::from() const { return d->from; } /// Sets the stanza's sender JID. /// /// \param from void QXmppStanza::setFrom(const QString& from) { d->from = from; } /// Returns the stanza's identifier. QString QXmppStanza::id() const { return d->id; } /// Sets the stanza's identifier. /// /// \param id void QXmppStanza::setId(const QString& id) { d->id = id; } /// Returns the stanza's language. QString QXmppStanza::lang() const { return d->lang; } /// Sets the stanza's language. /// /// \param lang void QXmppStanza::setLang(const QString& lang) { d->lang = lang; } /// Returns the stanza's error. QXmppStanza::Error QXmppStanza::error() const { return d->error; } /// Sets the stanza's error. /// /// \param error void QXmppStanza::setError(const QXmppStanza::Error& error) { d->error = error; } /// Returns the stanza's "extensions". /// /// Extensions are XML elements which are not handled internally by QXmpp. QXmppElementList QXmppStanza::extensions() const { return d->extensions; } /// Sets the stanza's "extensions". /// /// \param extensions void QXmppStanza::setExtensions(const QXmppElementList &extensions) { d->extensions = extensions; } /// Returns the stanza's extended addresses as defined by /// XEP-0033: Extended Stanza Addressing. QList QXmppStanza::extendedAddresses() const { return d->extendedAddresses; } /// Sets the stanza's extended addresses as defined by /// XEP-0033: Extended Stanza Addressing. void QXmppStanza::setExtendedAddresses(const QList &addresses) { d->extendedAddresses = addresses; } /// \cond void QXmppStanza::generateAndSetNextId() { // get back ++s_uniqeIdNo; d->id = "qxmpp" + QString::number(s_uniqeIdNo); } void QXmppStanza::parse(const QDomElement &element) { d->from = element.attribute("from"); d->to = element.attribute("to"); d->id = element.attribute("id"); d->lang = element.attribute("lang"); QDomElement errorElement = element.firstChildElement("error"); if(!errorElement.isNull()) d->error.parse(errorElement); // XEP-0033: Extended Stanza Addressing QDomElement addressElement = element.firstChildElement("addresses").firstChildElement("address"); while (!addressElement.isNull()) { QXmppExtendedAddress address; address.parse(addressElement); if (address.isValid()) d->extendedAddresses << address; addressElement = addressElement.nextSiblingElement("address"); } } void QXmppStanza::extensionsToXml(QXmlStreamWriter *xmlWriter) const { // XEP-0033: Extended Stanza Addressing if (!d->extendedAddresses.isEmpty()) { xmlWriter->writeStartElement("addresses"); xmlWriter->writeAttribute("xmlns", ns_extended_addressing); foreach (const QXmppExtendedAddress &address, d->extendedAddresses) address.toXml(xmlWriter); xmlWriter->writeEndElement(); } // other extensions foreach (const QXmppElement &extension, d->extensions) extension.toXml(xmlWriter); } /// \endcond qxmpp-0.9.3/src/base/QXmppStanza.h000066400000000000000000000123101263006255200167660ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * Georg Rudoy * * Source: * https://github.com/qxmpp-project/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 #include #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 #include "QXmppElement.h" class QXmppExtendedAddressPrivate; /// \brief Represents an extended address as defined by XEP-0033: Extended Stanza Addressing. /// /// Extended addresses maybe of different types: some are defined by XEP-0033, /// others are defined in separate XEPs (for instance XEP-0146: Remote Controlling Clients). /// That is why the "type" property is a string rather than an enumerated type. class QXMPP_EXPORT QXmppExtendedAddress { public: QXmppExtendedAddress(); QXmppExtendedAddress(const QXmppExtendedAddress&); ~QXmppExtendedAddress(); QXmppExtendedAddress& operator=(const QXmppExtendedAddress&); QString description() const; void setDescription(const QString &description); QString jid() const; void setJid(const QString &jid); QString type() const; void setType(const QString &type); bool isDelivered() const; void setDelivered(bool); bool isValid() const; /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; /// \endcond private: QSharedDataPointer d; }; class QXmppStanzaPrivate; /// \defgroup Stanzas /// \brief The QXmppStanza class is the base class for all XMPP stanzas. /// /// \ingroup Stanzas class QXMPP_EXPORT QXmppStanza { public: class QXMPP_EXPORT 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 = QString()); Error(const QString& type, const QString& cond, const QString& text = QString()); 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; /// \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(const QXmppStanza &other); virtual ~QXmppStanza(); QXmppStanza& operator=(const QXmppStanza &other); 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); QList extendedAddresses() const; void setExtendedAddresses(const QList &extendedAddresses); /// \cond virtual void parse(const QDomElement &element); virtual void toXml(QXmlStreamWriter *writer) const = 0; protected: void extensionsToXml(QXmlStreamWriter *writer) const; void generateAndSetNextId(); /// \endcond private: QSharedDataPointer d; static uint s_uniqeIdNo; }; #endif // QXMPPSTANZA_H qxmpp-0.9.3/src/base/QXmppStream.cpp000066400000000000000000000146441263006255200173300ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppStanza.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; // incoming 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).msecsTo(QTime::currentTime()) ^ reinterpret_cast(this)); randomSeeded = true; } } /// Destroys a base XMPP stream. QXmppStream::~QXmppStream() { delete d; } /// Disconnects from the remote host. /// void QXmppStream::disconnectFromHost() { if (d->socket) { if (d->socket->state() == QAbstractSocket::ConnectedState) { sendData(streamRootElementEnd); d->socket->flush(); } // FIXME: according to RFC 6120 section 4.4, we should wait for // the incoming stream to end before closing the socket 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 QXmppStanza &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(encrypted()), this, SLOT(_q_socketEncrypted())); Q_ASSERT(check); check = connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(_q_socketError(QAbstractSocket::SocketError))); Q_ASSERT(check); check = connect(socket, SIGNAL(readyRead()), this, SLOT(_q_socketReadyRead())); 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_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()); // handle whitespace pings if (!d->dataBuffer.isEmpty() && d->dataBuffer.trimmed().isEmpty()) { d->dataBuffer.clear(); handleStanza(QDomElement()); } // 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 // // NOTE: as we may only have partial XML content, do not alter the stream's // state until we have a valid XML document! 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); bool streamEnd = false; if (strData.contains(endStreamRegex)) streamEnd = true; else 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(); // process stream start if (streamStart) { d->streamStart = startStreamRegex.cap(0).toUtf8(); handleStream(doc.documentElement()); } // process stanzas QDomElement nodeRecv = doc.documentElement().firstChildElement(); while (!nodeRecv.isNull()) { handleStanza(nodeRecv); nodeRecv = nodeRecv.nextSiblingElement(); } // process stream end if (streamEnd) disconnectFromHost(); } qxmpp-0.9.3/src/base/QXmppStream.h000066400000000000000000000042351263006255200167700ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXmppStanza; class QXmppStreamPrivate; /// \brief The QXmppStream class is the base class for all XMPP streams. /// class QXMPP_EXPORT QXmppStream : public QXmppLoggable { Q_OBJECT public: QXmppStream(QObject *parent); ~QXmppStream(); virtual bool isConnected() const; bool sendPacket(const QXmppStanza&); 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_socketEncrypted(); void _q_socketError(QAbstractSocket::SocketError error); void _q_socketReadyRead(); private: QXmppStreamPrivate * const d; }; #endif // QXMPPSTREAM_H qxmpp-0.9.3/src/base/QXmppStreamFeatures.cpp000066400000000000000000000124561263006255200210260ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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; } QStringList QXmppStreamFeatures::authMechanisms() const { return m_authMechanisms; } void QXmppStreamFeatures::setAuthMechanisms(const QStringList &mechanisms) { m_authMechanisms = mechanisms; } QStringList QXmppStreamFeatures::compressionMethods() const { return m_compressionMethods; } void QXmppStreamFeatures::setCompressionMethods(const QStringList &methods) { m_compressionMethods = methods; } QXmppStreamFeatures::Mode QXmppStreamFeatures::tlsMode() const { return m_tlsMode; } void QXmppStreamFeatures::setTlsMode(QXmppStreamFeatures::Mode mode) { m_tlsMode = mode; } /// \cond 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()) { m_compressionMethods << subElement.text(); 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()) { m_authMechanisms << subElement.text(); 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); foreach (const QString &method, m_compressionMethods) writer->writeTextElement("method", method); writer->writeEndElement(); } if (!m_authMechanisms.isEmpty()) { writer->writeStartElement("mechanisms"); writer->writeAttribute("xmlns", ns_sasl); foreach (const QString &mechanism, m_authMechanisms) writer->writeTextElement("mechanism", mechanism); writer->writeEndElement(); } writer->writeEndElement(); } /// \endcond qxmpp-0.9.3/src/base/QXmppStreamFeatures.h000066400000000000000000000034341263006255200204670ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppStanza.h" class QXMPP_EXPORT 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); QStringList authMechanisms() const; void setAuthMechanisms(const QStringList &mechanisms); QStringList compressionMethods() const; void setCompressionMethods(const QStringList &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; QStringList m_authMechanisms; QStringList m_compressionMethods; }; #endif qxmpp-0.9.3/src/base/QXmppStreamInitiationIq.cpp000066400000000000000000000070571263006255200216520ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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_p.h" #include "QXmppUtils.h" QXmppDataForm QXmppStreamInitiationIq::featureForm() const { return m_featureForm; } void QXmppStreamInitiationIq::setFeatureForm(const QXmppDataForm &form) { m_featureForm = form; } QXmppTransferFileInfo QXmppStreamInitiationIq::fileInfo() const { return m_fileInfo; } void QXmppStreamInitiationIq::setFileInfo(const QXmppTransferFileInfo &fileInfo) { m_fileInfo = fileInfo; } 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; } QString QXmppStreamInitiationIq::siId() const { return m_siId; } void QXmppStreamInitiationIq::setSiId(const QString &id) { m_siId = id; } /// \cond 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()) { if (itemElement.tagName() == "feature" && itemElement.namespaceURI() == ns_feature_negotiation) { m_featureForm.parse(itemElement.firstChildElement()); } else if (itemElement.tagName() == "file" && itemElement.namespaceURI() == ns_stream_initiation_file_transfer) { m_fileInfo.parse(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); if (!m_fileInfo.isNull()) m_fileInfo.toXml(writer); if (!m_featureForm.isNull()) { writer->writeStartElement("feature"); writer->writeAttribute("xmlns", ns_feature_negotiation); m_featureForm.toXml(writer); writer->writeEndElement(); } writer->writeEndElement(); } /// \endcond qxmpp-0.9.3/src/base/QXmppStreamInitiationIq_p.h000066400000000000000000000041521263006255200216270ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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_P_H #define QXMPPSTREAMINITIATIONIQ_P_H #include #include "QXmppDataForm.h" #include "QXmppIq.h" #include "QXmppTransferManager.h" // // W A R N I N G // ------------- // // This file is not part of the QXmpp API. It exists for the convenience // of the QXmppTransferManager class. // // This header file may change from version to version without notice, // or even be removed. // // We mean it. // class QXMPP_AUTOTEST_EXPORT QXmppStreamInitiationIq : public QXmppIq { public: enum Profile { None = 0, FileTransfer }; QXmppDataForm featureForm() const; void setFeatureForm(const QXmppDataForm &form); QXmppTransferFileInfo fileInfo() const; void setFileInfo(const QXmppTransferFileInfo &info); 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); static bool isStreamInitiationIq(const QDomElement &element); protected: /// \cond void parseElementFromChild(const QDomElement &element); void toXmlElementFromChild(QXmlStreamWriter *writer) const; /// \endcond private: QXmppDataForm m_featureForm; QXmppTransferFileInfo m_fileInfo; QString m_mimeType; Profile m_profile; QString m_siId; }; #endif qxmpp-0.9.3/src/base/QXmppStun.cpp000066400000000000000000002464711263006255200170330ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 #include "QXmppStun_p.h" #include "QXmppUtils.h" #define STUN_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; static const char* gathering_states[] = { "new", "gathering", "complete" }; static const char* pair_states[] = { "frozen", "waiting", "in-progress", "succeeded", "failed" }; 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 QString computeFoundation(QXmppJingleCandidate::Type type, const QString &protocol, const QHostAddress &baseAddress) { QCryptographicHash hash(QCryptographicHash::Md5); hash.addData((QString::number(type) + protocol + baseAddress.toString()).toUtf8()); return hash.result().toHex(); } 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 isLoopbackAddress(const QHostAddress &addr) { return (addr.toIPv4Address() & 0xff000000) == 0x7f000000; } // Returns true if the two addresses are compatible. static bool isCompatibleAddress(const QHostAddress &a1, const QHostAddress &a2) { return a1.protocol() == a2.protocol() && isIPv6LinkLocalAddress(a1) == isIPv6LinkLocalAddress(a2); } 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(STUN_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() == STUN_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 != QXmppUtils::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 = QXmppUtils::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 = QXmppUtils::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 = QXmppUtils::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(STUN_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::fromLatin1(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::fromLatin1(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::fromLatin1(iceControlling.toHex())); if (!iceControlled.isEmpty()) dumpLines << QString(" * ICE-CONTROLLED %1") .arg(QString::fromLatin1(iceControlled.toHex())); if (useCandidate) dumpLines << QString(" * USE-CANDIDATE"); 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_retryTimer->start(0); } void QXmppStunTransaction::readStun(const QXmppStunMessage &response) { if (response.messageClass() == QXmppStunMessage::Error || response.messageClass() == QXmppStunMessage::Response) { m_response = response; m_retryTimer->stop(); 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 emit writeStun(m_request); m_retryTimer->start(m_tries ? 2 * m_retryTimer->interval() : STUN_RTO_INTERVAL); m_tries++; } /// Constructs a new QXmppTurnAllocation. /// /// \param parent QXmppTurnAllocation::QXmppTurnAllocation(QObject *parent) : QXmppIceTransport(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(QXmppUtils::generateRandomBytes(STUN_ID_SIZE)); 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(QXmppUtils::generateRandomBytes(STUN_ID_SIZE)); 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); } } QXmppJingleCandidate QXmppTurnAllocation::localCandidate(int component) const { QXmppJingleCandidate candidate; candidate.setComponent(component); candidate.setHost(relayedHost()); candidate.setId(QXmppUtils::generateStanzaHash(10)); candidate.setPort(relayedPort()); candidate.setProtocol("udp"); candidate.setType(QXmppJingleCandidate::RelayedType); candidate.setPriority(candidatePriority(candidate)); candidate.setFoundation(computeFoundation( candidate.type(), candidate.protocol(), candidate.host())); return candidate; } 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(QXmppUtils::generateRandomBytes(STUN_ID_SIZE)); 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(QXmppUtils::generateRandomBytes(STUN_ID_SIZE)); 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(QXmppUtils::generateRandomBytes(STUN_ID_SIZE)); 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(QXmppUtils::generateRandomBytes(STUN_ID_SIZE)); 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 } QXmppUdpTransport::QXmppUdpTransport(QUdpSocket *socket, QObject *parent) : QXmppIceTransport(parent) , m_socket(socket) { bool check; Q_UNUSED(check); check = connect(m_socket, SIGNAL(readyRead()), this, SLOT(readyRead())); Q_ASSERT(check); } QXmppUdpTransport::~QXmppUdpTransport() { } void QXmppUdpTransport::disconnectFromHost() { m_socket->close(); } QXmppJingleCandidate QXmppUdpTransport::localCandidate(int component) const { QXmppJingleCandidate candidate; candidate.setComponent(component); // remove scope ID from IPv6 non-link local addresses QHostAddress addr(m_socket->localAddress()); if (addr.protocol() == QAbstractSocket::IPv6Protocol && !isIPv6LinkLocalAddress(addr)) { addr.setScopeId(QString()); } candidate.setHost(addr); candidate.setId(QXmppUtils::generateStanzaHash(10)); candidate.setPort(m_socket->localPort()); candidate.setProtocol("udp"); candidate.setType(QXmppJingleCandidate::HostType); candidate.setPriority(candidatePriority(candidate)); candidate.setFoundation(computeFoundation( candidate.type(), candidate.protocol(), candidate.host())); return candidate; } void QXmppUdpTransport::readyRead() { QByteArray buffer; QHostAddress remoteHost; quint16 remotePort; while (m_socket->hasPendingDatagrams()) { const qint64 size = m_socket->pendingDatagramSize(); buffer.resize(size); m_socket->readDatagram(buffer.data(), buffer.size(), &remoteHost, &remotePort); emit datagramReceived(buffer, remoteHost, remotePort); } } qint64 QXmppUdpTransport::writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port) { QHostAddress remoteHost = host; if (isIPv6LinkLocalAddress(host)) remoteHost.setScopeId(m_socket->localAddress().scopeId()); return m_socket->writeDatagram(data, remoteHost, port); } class CandidatePair : public QXmppLoggable { public: enum State { FrozenState, WaitingState, InProgressState, SucceededState, FailedState }; CandidatePair(int component, bool controlling, QObject *parent); quint64 priority() const; State state() const; void setState(State state); QString toString() const; bool nominated; bool nominating; QXmppJingleCandidate remote; QXmppJingleCandidate reflexive; QXmppIceTransport *transport; QXmppStunTransaction *transaction; private: int m_component; bool m_controlling; State m_state; }; static bool candidatePairPtrLessThan(const CandidatePair *p1, const CandidatePair *p2) { return p1->priority() > p2->priority(); } CandidatePair::CandidatePair(int component, bool controlling, QObject *parent) : QXmppLoggable(parent) , nominated(false) , nominating(false) , transport(0) , transaction(0) , m_component(component) , m_controlling(controlling) , m_state(WaitingState) { } quint64 CandidatePair::priority() const { const QXmppJingleCandidate local = transport->localCandidate(m_component); // 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); } CandidatePair::State CandidatePair::state() const { return m_state; } void CandidatePair::setState(CandidatePair::State state) { m_state = state; info(QString("ICE pair changed to state %1 %2").arg(QLatin1String(pair_states[state]), toString())); } QString CandidatePair::toString() const { const QXmppJingleCandidate candidate = transport->localCandidate(m_component); QString str = QString("%1 port %2").arg(remote.host().toString(), QString::number(remote.port())); if (candidate.type() == QXmppJingleCandidate::HostType) str += QString(" (local %1 port %2)").arg(candidate.host().toString(), QString::number(candidate.port())); 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; } class QXmppIcePrivate { public: QXmppIcePrivate(); bool iceControlling; QString localUser; QString localPassword; QString remoteUser; QString remotePassword; QHostAddress stunHost; quint16 stunPort; QByteArray tieBreaker; }; QXmppIcePrivate::QXmppIcePrivate() : iceControlling(false) , stunPort(0) { localUser = QXmppUtils::generateStanzaHash(4); localPassword = QXmppUtils::generateStanzaHash(22); tieBreaker = QXmppUtils::generateRandomBytes(8); } class QXmppIceComponentPrivate { public: QXmppIceComponentPrivate(int component, QXmppIcePrivate *config, QXmppIceComponent *qq); bool addRemoteCandidate(const QXmppJingleCandidate &candidate); CandidatePair* findPair(QXmppStunTransaction *transaction); void performCheck(CandidatePair *pair, bool nominate); void setSockets(QList sockets); void setTurnServer(const QHostAddress &host, quint16 port); void setTurnUser(const QString &user); void setTurnPassword(const QString &password); void writeStun(const QXmppStunMessage &message, QXmppIceTransport *transport, const QHostAddress &remoteHost, quint16 remotePort); CandidatePair *activePair; const int component; const QXmppIcePrivate* const config; CandidatePair *fallbackPair; QXmppIceConnection::GatheringState gatheringState; QList localCandidates; quint32 peerReflexivePriority; QList remoteCandidates; QList pairs; QList transports; QTimer *timer; // STUN server QMap stunTransactions; // TURN server QXmppTurnAllocation *turnAllocation; bool turnConfigured; private: QXmppIceComponent *q; }; QXmppIceComponentPrivate::QXmppIceComponentPrivate(int component_, QXmppIcePrivate *config_, QXmppIceComponent *qq) : activePair(0) , component(component_) , config(config_) , fallbackPair(0) , gatheringState(QXmppIceConnection::NewGatheringState) , peerReflexivePriority(0) , timer(0) , turnAllocation(0) , turnConfigured(false) , q(qq) { } bool QXmppIceComponentPrivate::addRemoteCandidate(const QXmppJingleCandidate &candidate) { if (candidate.component() != 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 (const QXmppJingleCandidate &c, remoteCandidates) if (c.host() == candidate.host() && c.port() == candidate.port()) return false; remoteCandidates << candidate; foreach (QXmppIceTransport *transport, transports) { // only pair compatible addresses const QXmppJingleCandidate local = transport->localCandidate(component); if (!isCompatibleAddress(local.host(), candidate.host())) continue; CandidatePair *pair = new CandidatePair(component, config->iceControlling, q); pair->remote = candidate; pair->transport = transport; pairs << pair; if (!fallbackPair && local.type() == QXmppJingleCandidate::HostType) fallbackPair = pair; } qSort(pairs.begin(), pairs.end(), candidatePairPtrLessThan); return true; } CandidatePair* QXmppIceComponentPrivate::findPair(QXmppStunTransaction *transaction) { foreach (CandidatePair *pair, pairs) { if (pair->transaction == transaction) return pair; } return 0; } void QXmppIceComponentPrivate::performCheck(CandidatePair *pair, bool nominate) { QXmppStunMessage message; message.setId(QXmppUtils::generateRandomBytes(STUN_ID_SIZE)); message.setType(QXmppStunMessage::Binding | QXmppStunMessage::Request); message.setPriority(peerReflexivePriority); message.setUsername(QString("%1:%2").arg(config->remoteUser, config->localUser)); if (config->iceControlling) { message.iceControlling = config->tieBreaker; message.useCandidate = true; } else { message.iceControlled = config->tieBreaker; } pair->nominating = nominate; pair->setState(CandidatePair::InProgressState); pair->transaction = new QXmppStunTransaction(message, q); } void QXmppIceComponentPrivate::setSockets(QList sockets) { bool check; Q_UNUSED(check); // clear previous candidates and sockets localCandidates.clear(); foreach (CandidatePair *pair, pairs) delete pair; pairs.clear(); foreach (QXmppIceTransport *transport, transports) if (transport != turnAllocation) delete transport; transports.clear(); // store candidates foreach (QUdpSocket *socket, sockets) { socket->setParent(q); QXmppUdpTransport *transport = new QXmppUdpTransport(socket, q); check = QObject::connect(transport, SIGNAL(datagramReceived(QByteArray,QHostAddress,quint16)), q, SLOT(handleDatagram(QByteArray,QHostAddress,quint16))); Q_ASSERT(check); QXmppJingleCandidate candidate = transport->localCandidate(component); transports << transport; localCandidates << candidate; } // start STUN checks if (!config->stunHost.isNull() && config->stunPort) { stunTransactions.clear(); QXmppStunMessage request; request.setType(QXmppStunMessage::Binding | QXmppStunMessage::Request); foreach (QXmppIceTransport *transport, transports) { const QXmppJingleCandidate local = transport->localCandidate(component); if (!isCompatibleAddress(local.host(), config->stunHost)) continue; request.setId(QXmppUtils::generateRandomBytes(STUN_ID_SIZE)); QXmppStunTransaction *transaction = new QXmppStunTransaction(request, q); stunTransactions.insert(transaction, transport); } } // connect to TURN server if (turnConfigured) { transports << turnAllocation; turnAllocation->connectToHost(); } q->updateGatheringState(); } void QXmppIceComponentPrivate::setTurnServer(const QHostAddress &host, quint16 port) { turnAllocation->setServer(host, port); turnConfigured = !host.isNull() && port; } void QXmppIceComponentPrivate::setTurnUser(const QString &user) { turnAllocation->setUser(user); } void QXmppIceComponentPrivate::setTurnPassword(const QString &password) { turnAllocation->setPassword(password); } void QXmppIceComponentPrivate::writeStun(const QXmppStunMessage &message, QXmppIceTransport *transport, const QHostAddress &address, quint16 port) { const QString messagePassword = (message.type() & 0xFF00) ? config->localPassword : config->remotePassword; const QByteArray data = message.encode(messagePassword.toUtf8()); transport->writeDatagram(data, address, port); #ifdef QXMPP_DEBUG_STUN q->logSent(QString("STUN packet to %1 port %2\n%3").arg( address.toString(), QString::number(port), message.toString())); #endif } /// Constructs a new QXmppIceComponent. /// /// \param parent QXmppIceComponent::QXmppIceComponent(int component, QXmppIcePrivate *config, QObject *parent) : QXmppLoggable(parent) { bool check; Q_UNUSED(check); d = new QXmppIceComponentPrivate(component, config, this); d->timer = new QTimer(this); d->timer->setInterval(500); check = connect(d->timer, SIGNAL(timeout()), this, SLOT(checkCandidates())); Q_ASSERT(check); d->turnAllocation = new QXmppTurnAllocation(this); check = connect(d->turnAllocation, SIGNAL(connected()), this, SLOT(turnConnected())); Q_ASSERT(check); check = connect(d->turnAllocation, SIGNAL(datagramReceived(QByteArray,QHostAddress,quint16)), this, SLOT(handleDatagram(QByteArray,QHostAddress,quint16))); Q_ASSERT(check); check = connect(d->turnAllocation, SIGNAL(disconnected()), this, SLOT(updateGatheringState())); Q_ASSERT(check); // calculate peer-reflexive candidate priority // see RFC 5245 - 7.1.2.1. PRIORITY and USE-CANDIDATE QXmppJingleCandidate reflexive; reflexive.setComponent(d->component); reflexive.setType(QXmppJingleCandidate::PeerReflexiveType); d->peerReflexivePriority = candidatePriority(reflexive); setObjectName(QString("STUN(%1)").arg(QString::number(d->component))); } /// Destroys the QXmppIceComponent. QXmppIceComponent::~QXmppIceComponent() { foreach (CandidatePair *pair, d->pairs) delete pair; delete d; } /// Returns the component id for the current socket, e.g. 1 for RTP /// and 2 for RTCP. int QXmppIceComponent::component() const { return d->component; } void QXmppIceComponent::checkCandidates() { if (d->config->remoteUser.isEmpty()) return; debug("Checking remote candidates"); foreach (CandidatePair *pair, d->pairs) { if (pair->state() == CandidatePair::WaitingState) { d->performCheck(pair, d->config->iceControlling); break; } } } /// Stops ICE connectivity checks and closes the underlying sockets. void QXmppIceComponent::close() { foreach (QXmppIceTransport *transport, d->transports) transport->disconnectFromHost(); d->turnAllocation->disconnectFromHost(); d->timer->stop(); d->activePair = 0; } /// Starts ICE connectivity checks. void QXmppIceComponent::connectToHost() { if (d->activePair) return; checkCandidates(); d->timer->start(); } /// Returns true if ICE negotiation completed, false otherwise. bool QXmppIceComponent::isConnected() const { return d->activePair != 0; } /// Returns the list of local candidates. QList QXmppIceComponent::localCandidates() const { return d->localCandidates; } void QXmppIceComponent::handleDatagram(const QByteArray &buffer, const QHostAddress &remoteHost, quint16 remotePort) { QXmppIceTransport *transport = qobject_cast(sender()); if (!transport) return; // 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 (CandidatePair *pair, d->pairs) { if (pair->remote.host() == remoteHost && pair->remote.port() == remotePort) { d->fallbackPair = pair; break; } } emit datagramReceived(buffer); return; } // check if it's STUN QXmppStunTransaction *stunTransaction = 0; foreach (QXmppStunTransaction *t, d->stunTransactions.keys()) { if (t->request().id() == messageId && d->stunTransactions.value(t) == transport) { stunTransaction = t; break; } } // determine password to use QString messagePassword; if (!stunTransaction) { messagePassword = (messageType & 0xFF00) ? d->config->remotePassword : d->config->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 // we only want binding requests and responses if (message.messageMethod() != QXmppStunMessage::Binding) return; // STUN checks if (stunTransaction) { stunTransaction->readStun(message); return; } // process message from peer CandidatePair *pair = 0; if (message.messageClass() == QXmppStunMessage::Request) { // check for role conflict if (d->config->iceControlling && (!message.iceControlling.isEmpty() || message.useCandidate)) { warning("Role conflict, expected to be controlling"); return; } else if (!d->config->iceControlling && !message.iceControlled.isEmpty()) { warning("Role conflict, expected to be controlled"); return; } // send a binding response QXmppStunMessage response; response.setId(message.id()); response.setType(QXmppStunMessage::Binding | QXmppStunMessage::Response); response.xorMappedHost = remoteHost; response.xorMappedPort = remotePort; d->writeStun(response, transport, remoteHost, remotePort); // find or create remote candidate QXmppJingleCandidate remoteCandidate; bool remoteCandidateFound = false; foreach (const QXmppJingleCandidate &c, d->remoteCandidates) { if (c.host() == remoteHost && c.port() == remotePort) { remoteCandidate = c; remoteCandidateFound = true; break; } } if (!remoteCandidateFound) { // 7.2.1.3. Learning Peer Reflexive Candidates remoteCandidate.setComponent(d->component); remoteCandidate.setHost(remoteHost); remoteCandidate.setId(QXmppUtils::generateStanzaHash(10)); remoteCandidate.setPort(remotePort); remoteCandidate.setPriority(message.priority()); remoteCandidate.setProtocol("udp"); remoteCandidate.setType(QXmppJingleCandidate::PeerReflexiveType); remoteCandidate.setFoundation(QXmppUtils::generateStanzaHash(32)); d->remoteCandidates << remoteCandidate; } // construct pair foreach (CandidatePair *ptr, d->pairs) { if (ptr->transport == transport && ptr->remote.host() == remoteHost && ptr->remote.port() == remotePort) { pair = ptr; break; } } if (!pair) { pair = new CandidatePair(d->component, d->config->iceControlling, this); pair->remote = remoteCandidate; pair->transport = transport; d->pairs << pair; qSort(d->pairs.begin(), d->pairs.end(), candidatePairPtrLessThan); } switch (pair->state()) { case CandidatePair::FrozenState: case CandidatePair::WaitingState: case CandidatePair::FailedState: // send a triggered connectivity test if (!d->config->remoteUser.isEmpty()) d->performCheck(pair, pair->nominating || d->config->iceControlling || message.useCandidate); break; case CandidatePair::InProgressState: // FIXME: force retransmit now pair->nominating = pair->nominating || message.useCandidate; break; case CandidatePair::SucceededState: if (message.useCandidate) pair->nominated = true; break; } } else if (message.messageClass() == QXmppStunMessage::Response || message.messageClass() == QXmppStunMessage::Error) { // find the pair for this transaction foreach (CandidatePair *ptr, d->pairs) { if (ptr->transaction && ptr->transaction->request().id() == message.id()) { pair = ptr; break; } } if (!pair) return; // check remote host and port if (remoteHost != pair->remote.host() || remotePort != pair->remote.port()) { QXmppStunMessage error; error.setType(QXmppStunMessage::Error); error.errorPhrase = QString("Received response from unexpected %1:%1").arg( remoteHost.toString(), QString::number(remotePort)); pair->transaction->readStun(error); return; } pair->transaction->readStun(message); } // signal completion if (pair && pair->nominated) { d->timer->stop(); if (!d->activePair || pair->priority() > d->activePair->priority()) { info(QString("ICE pair selected %1 (priority: %2)").arg( pair->toString(), QString::number(pair->priority()))); const bool wasConnected = (d->activePair != 0); d->activePair = pair; if (!wasConnected) emit connected(); } } } void QXmppIceComponent::transactionFinished() { QXmppStunTransaction *transaction = qobject_cast(sender()); transaction->deleteLater(); // ICE checks CandidatePair *pair = d->findPair(transaction); if (pair) { const QXmppStunMessage response = transaction->response(); if (response.messageClass() == QXmppStunMessage::Response) { // store peer-reflexive address if (!response.xorMappedHost.isNull() && response.xorMappedPort != 0) { pair->reflexive.setHost(response.xorMappedHost); pair->reflexive.setPort(response.xorMappedPort); } pair->setState(CandidatePair::SucceededState); if (pair->nominating) { // outgoing media can flow pair->nominated = true; } } else { debug(QString("ICE forward check failed %1 (error %2)").arg( pair->toString(), transaction->response().errorPhrase)); pair->setState(CandidatePair::FailedState); } pair->transaction = 0; return; } // STUN checks QXmppIceTransport *transport = d->stunTransactions.value(transaction); if (transport) { const QXmppStunMessage response = transaction->response(); if (response.messageClass() == QXmppStunMessage::Response) { // determine server-reflexive address QHostAddress reflexiveHost; quint16 reflexivePort = 0; if (!response.xorMappedHost.isNull() && response.xorMappedPort != 0) { reflexiveHost = response.xorMappedHost; reflexivePort = response.xorMappedPort; } else if (!response.mappedHost.isNull() && response.mappedPort != 0) { reflexiveHost = response.mappedHost; reflexivePort = response.mappedPort; } else { warning("STUN server did not provide a reflexive address"); return; } // check whether this candidates is already known foreach (const QXmppJingleCandidate &candidate, d->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(d->component); candidate.setHost(reflexiveHost); candidate.setId(QXmppUtils::generateStanzaHash(10)); candidate.setPort(reflexivePort); candidate.setProtocol("udp"); candidate.setType(QXmppJingleCandidate::ServerReflexiveType); candidate.setPriority(candidatePriority(candidate)); candidate.setFoundation(computeFoundation( candidate.type(), candidate.protocol(), transport->localCandidate(d->component).host())); d->localCandidates << candidate; emit localCandidatesChanged(); } else { debug(QString("STUN test failed (error %1)").arg( transaction->response().errorPhrase)); } d->stunTransactions.remove(transaction); updateGatheringState(); return; } } void QXmppIceComponent::turnConnected() { const QXmppJingleCandidate candidate = d->turnAllocation->localCandidate(d->component); // add the new local candidate debug(QString("Adding relayed candidate %1 port %2").arg( candidate.host().toString(), QString::number(candidate.port()))); d->localCandidates << candidate; emit localCandidatesChanged(); updateGatheringState(); } 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; // FIXME: for some reason we can have loopback addresses // even if the interface does not have the loopback flag if (isLoopbackAddress(ip)) continue; // 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) { CandidatePair *pair = d->activePair ? d->activePair : d->fallbackPair; if (!pair) return -1; return pair->transport->writeDatagram(datagram, pair->remote.host(), pair->remote.port()); } void QXmppIceComponent::updateGatheringState() { QXmppIceConnection::GatheringState newGatheringState; if (d->transports.isEmpty()) newGatheringState = QXmppIceConnection::NewGatheringState; else if (!d->stunTransactions.isEmpty() || d->turnAllocation->state() == QXmppTurnAllocation::ConnectingState) newGatheringState = QXmppIceConnection::BusyGatheringState; else newGatheringState = QXmppIceConnection::CompleteGatheringState; if (newGatheringState != d->gatheringState) { d->gatheringState = newGatheringState; emit gatheringStateChanged(); } } void QXmppIceComponent::writeStun(const QXmppStunMessage &message) { QXmppStunTransaction *transaction = qobject_cast(sender()); // ICE checks CandidatePair *pair = d->findPair(transaction); if (pair) { d->writeStun(message, pair->transport, pair->remote.host(), pair->remote.port()); return; } // STUN checks QXmppIceTransport *transport = d->stunTransactions.value(transaction); if (transport) { transport->writeDatagram(message.encode(), d->config->stunHost, d->config->stunPort); #ifdef QXMPP_DEBUG_STUN logSent(QString("STUN packet to %1 port %2\n%3").arg( d->config->stunHost.toString(), QString::number(d->config->stunPort), message.toString())); #endif return; } } class QXmppIceConnectionPrivate : public QXmppIcePrivate { public: QXmppIceConnectionPrivate(); QMap components; QTimer *connectTimer; QXmppIceConnection::GatheringState gatheringState; QHostAddress turnHost; quint16 turnPort; QString turnUser; QString turnPassword; }; QXmppIceConnectionPrivate::QXmppIceConnectionPrivate() : gatheringState(QXmppIceConnection::NewGatheringState) , turnPort(0) { } /// Constructs a new ICE connection. /// /// \param parent QXmppIceConnection::QXmppIceConnection(QObject *parent) : QXmppLoggable(parent) , d(new QXmppIceConnectionPrivate()) { bool check; // timer to limit connection time to 30 seconds d->connectTimer = new QTimer(this); d->connectTimer->setInterval(30000); d->connectTimer->setSingleShot(true); check = connect(d->connectTimer, SIGNAL(timeout()), this, SLOT(slotTimeout())); Q_ASSERT(check); Q_UNUSED(check); } QXmppIceConnection::~QXmppIceConnection() { delete d; } /// Returns the given component of this ICE connection. /// /// \param component QXmppIceComponent *QXmppIceConnection::component(int component) { return d->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 (d->components.contains(component)) { warning(QString("Already have component %1").arg(QString::number(component))); return; } QXmppIceComponent *socket = new QXmppIceComponent(component, d, this); socket->d->setTurnServer(d->turnHost, d->turnPort); socket->d->setTurnUser(d->turnUser); socket->d->setTurnPassword(d->turnPassword); check = connect(socket, SIGNAL(localCandidatesChanged()), this, SIGNAL(localCandidatesChanged())); Q_ASSERT(check); check = connect(socket, SIGNAL(connected()), this, SLOT(slotConnected())); Q_ASSERT(check); check = connect(socket, SIGNAL(gatheringStateChanged()), this, SLOT(slotGatheringStateChanged())); Q_ASSERT(check); d->components[component] = socket; } /// Adds a candidate for one of the remote components. /// /// \param candidate void QXmppIceConnection::addRemoteCandidate(const QXmppJingleCandidate &candidate) { QXmppIceComponent *socket = d->components.value(candidate.component()); if (!socket) { warning(QString("Not adding candidate for unknown component %1").arg( QString::number(candidate.component()))); return; } socket->d->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, d->components.size()); if (sockets.isEmpty() && !addresses.isEmpty()) return false; // assign sockets QList keys = d->components.keys(); qSort(keys); int s = 0; foreach (int k, keys) { d->components[k]->d->setSockets(sockets.mid(s, addresses.size())); s += addresses.size(); } return true; } /// Closes the ICE connection. void QXmppIceConnection::close() { d->connectTimer->stop(); foreach (QXmppIceComponent *socket, d->components.values()) socket->close(); } /// Starts ICE connectivity checks. void QXmppIceConnection::connectToHost() { if (isConnected() || d->connectTimer->isActive()) return; foreach (QXmppIceComponent *socket, d->components.values()) socket->connectToHost(); d->connectTimer->start(); } /// Returns true if ICE negotiation completed, false otherwise. bool QXmppIceConnection::isConnected() const { foreach (QXmppIceComponent *socket, d->components.values()) if (!socket->isConnected()) return false; return true; } /// Returns the ICE gathering state, that is the discovery of /// local candidates. QXmppIceConnection::GatheringState QXmppIceConnection::gatheringState() const { return d->gatheringState; } /// Sets whether the local party has the ICE controlling role. /// /// \a note This must be called only once, immediately after creating /// the connection. void QXmppIceConnection::setIceControlling(bool controlling) { d->iceControlling = 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, d->components.values()) candidates += socket->localCandidates(); return candidates; } /// Returns the local user fragment. QString QXmppIceConnection::localUser() const { return d->localUser; } /// Returns the local password. QString QXmppIceConnection::localPassword() const { return d->localPassword; } /// Sets the remote user fragment. /// /// \param user void QXmppIceConnection::setRemoteUser(const QString &user) { d->remoteUser = user; } /// Sets the remote password. /// /// \param password void QXmppIceConnection::setRemotePassword(const QString &password) { d->remotePassword = password; } /// Sets the STUN server to use to determine server-reflexive addresses /// and ports. /// /// \note This may only be called prior to calling bind(). /// /// \param host The address of the STUN server. /// \param port The port of the STUN server. void QXmppIceConnection::setStunServer(const QHostAddress &host, quint16 port) { d->stunHost = host; d->stunPort = port; } /// Sets the TURN server to use to relay packets in double-NAT configurations. /// /// \note This may only be called prior to calling bind(). /// /// \param host The address of the TURN server. /// \param port The port of the TURN server. void QXmppIceConnection::setTurnServer(const QHostAddress &host, quint16 port) { d->turnHost = host; d->turnPort = port; foreach (QXmppIceComponent *socket, d->components.values()) socket->d->setTurnServer(host, port); } /// Sets the \a user used for authentication with the TURN server. /// /// \note This may only be called prior to calling bind(). /// /// \param user void QXmppIceConnection::setTurnUser(const QString &user) { d->turnUser = user; foreach (QXmppIceComponent *socket, d->components.values()) socket->d->setTurnUser(user); } /// Sets the \a password used for authentication with the TURN server. /// /// \note This may only be called prior to calling bind(). /// /// \param password void QXmppIceConnection::setTurnPassword(const QString &password) { d->turnPassword = password; foreach (QXmppIceComponent *socket, d->components.values()) socket->d->setTurnPassword(password); } void QXmppIceConnection::slotConnected() { foreach (QXmppIceComponent *socket, d->components.values()) if (!socket->isConnected()) return; info(QString("ICE negotiation completed")); d->connectTimer->stop(); emit connected(); } void QXmppIceConnection::slotGatheringStateChanged() { GatheringState newGatheringState; bool allComplete = true; bool allNew = true; foreach (QXmppIceComponent *socket, d->components.values()) { if (socket->d->gatheringState != CompleteGatheringState) allComplete = false; if (socket->d->gatheringState != NewGatheringState) allNew = false; } if (allNew) newGatheringState = NewGatheringState; else if (allComplete) newGatheringState = CompleteGatheringState; else newGatheringState = BusyGatheringState; if (newGatheringState != d->gatheringState) { info(QString("ICE gathering state changed from '%1' to '%2'").arg( gathering_states[d->gatheringState], gathering_states[newGatheringState])); d->gatheringState = newGatheringState; emit gatheringStateChanged(); } } void QXmppIceConnection::slotTimeout() { warning(QString("ICE negotiation timed out")); foreach (QXmppIceComponent *socket, d->components.values()) socket->close(); emit disconnected(); } QXmppIceTransport::QXmppIceTransport(QObject *parent) : QXmppLoggable(parent) { } QXmppIceTransport::~QXmppIceTransport() { } qxmpp-0.9.3/src/base/QXmppStun.h000066400000000000000000000202441263006255200164640ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 CandidatePair; class QDataStream; class QUdpSocket; class QTimer; class QXmppIceComponentPrivate; class QXmppIceConnectionPrivate; class QXmppIcePrivate; /// \internal /// /// The QXmppStunMessage class represents a STUN message. /// class QXMPP_EXPORT 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; }; /// \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 QXMPP_EXPORT QXmppIceComponent : public QXmppLoggable { Q_OBJECT public: ~QXmppIceComponent(); int component() const; bool isConnected() const; QList localCandidates() const; 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 handleDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port); void turnConnected(); void transactionFinished(); void updateGatheringState(); void writeStun(const QXmppStunMessage &request); 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); /// \internal This signal is emitted when the gathering state of local candidates changes. void gatheringStateChanged(); /// \brief This signal is emitted when the list of local candidates changes. void localCandidatesChanged(); private: QXmppIceComponent(int component, QXmppIcePrivate *config, QObject *parent=0); QXmppIceComponentPrivate *d; friend class QXmppIceComponentPrivate; friend class QXmppIceConnection; }; /// \brief The QXmppIceConnection class represents a set of UDP sockets /// capable of performing Interactive Connectivity Establishment (RFC 5245). /// /// A typical example is: /// /// \code /// QXmppIceConnection *connection = new QXmppIceConnection(); /// connection->setIceControlling(true); /// connection->addComponent(1); /// /// // if needed, set STUN / TURN configuration /// // connection->setStunServer(..); /// // connection->setTurnServer(..); /// /// // start listening /// connection->bind(QXmppIceComponent::discoverAddresses()); /// /// // receive remote information: user, password, candidates /// // ... /// /// // set remote information and start connecting /// connection->setRemoteUser("foo"); /// connection->setRemoteUser("bar"); /// connection->addRemoteCandidate(..); /// connection->connectToHost(); /// /// \endcode class QXMPP_EXPORT QXmppIceConnection : public QXmppLoggable { Q_OBJECT Q_ENUMS(GatheringState) Q_PROPERTY(QXmppIceConnection::GatheringState gatheringState READ gatheringState NOTIFY gatheringStateChanged) public: enum GatheringState { NewGatheringState, BusyGatheringState, CompleteGatheringState }; QXmppIceConnection(QObject *parent = 0); ~QXmppIceConnection(); QXmppIceComponent *component(int component); void addComponent(int component); void setIceControlling(bool controlling); QList localCandidates() const; QString localUser() const; QString localPassword() const; 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; GatheringState gatheringState() 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 gathering state of local candidates changes. void gatheringStateChanged(); /// \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 slotGatheringStateChanged(); void slotTimeout(); private: QXmppIceConnectionPrivate *d; }; #endif qxmpp-0.9.3/src/base/QXmppStun_p.h000066400000000000000000000112411263006255200170000ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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_P_H #define QXMPPSTUN_P_H #include "QXmppStun.h" class QUdpSocket; class QTimer; // // W A R N I N G // ------------- // // This file is not part of the QXmpp API. // // This header file may change from version to version without notice, // or even be removed. // // We mean it. // /// \internal /// /// The QXmppStunTransaction class represents a STUN transaction. /// class QXMPP_EXPORT 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; }; class QXMPP_EXPORT QXmppIceTransport : public QXmppLoggable { Q_OBJECT public: QXmppIceTransport(QObject *parent = 0); ~QXmppIceTransport(); virtual QXmppJingleCandidate localCandidate(int component) const = 0; virtual qint64 writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port) = 0; public slots: virtual void disconnectFromHost() = 0; signals: /// \brief This signal is emitted when a data packet is received. void datagramReceived(const QByteArray &data, const QHostAddress &host, quint16 port); }; /// \internal /// /// The QXmppTurnAllocation class represents a TURN allocation as defined /// by RFC 5766 Traversal Using Relays around NAT (TURN). /// class QXMPP_EXPORT QXmppTurnAllocation : public QXmppIceTransport { 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); QXmppJingleCandidate localCandidate(int component) const; 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 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; }; /// \internal /// /// The QXmppUdpTransport class represents a UDP transport. /// class QXMPP_EXPORT QXmppUdpTransport : public QXmppIceTransport { Q_OBJECT public: QXmppUdpTransport(QUdpSocket *socket, QObject *parent = 0); ~QXmppUdpTransport(); QXmppJingleCandidate localCandidate(int component) const; qint64 writeDatagram(const QByteArray &data, const QHostAddress &host, quint16 port); public slots: void disconnectFromHost(); private slots: void readyRead(); private: QUdpSocket *m_socket; }; #endif qxmpp-0.9.3/src/base/QXmppUtils.cpp000066400000000000000000000243231263006255200171700ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 }; /// Parses a date-time from a string according to /// XEP-0082: XMPP Date and Time Profiles. QDateTime QXmppUtils::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; } /// Serializes a date-time to a string according to /// XEP-0082: XMPP Date and Time Profiles. QString QXmppUtils::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 according to /// XEP-0082: XMPP Date and Time Profiles. int QXmppUtils::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 according to /// XEP-0082: XMPP Date and Time Profiles. QString QXmppUtils::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"); } /// Returns the domain for the given \a jid. QString QXmppUtils::jidToDomain(const QString &jid) { return jidToBareJid(jid).split("@").last(); } /// Returns the resource for the given \a jid. QString QXmppUtils::jidToResource(const QString& jid) { const int pos = jid.indexOf(QChar('/')); if (pos < 0) return QString(); return jid.mid(pos+1); } /// Returns the user for the given \a jid. QString QXmppUtils::jidToUser(const QString &jid) { const int pos = jid.indexOf(QChar('@')); if (pos < 0) return QString(); return jid.left(pos); } /// Returns the bare jid (i.e. without resource) for the given \a jid. QString QXmppUtils::jidToBareJid(const QString& jid) { const int pos = jid.indexOf(QChar('/')); if (pos < 0) return jid; return jid.left(pos); } /// Calculates the CRC32 checksum for the given input. quint32 QXmppUtils::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(); } /// Generates the MD5 HMAC for the given \a key and \a text. QByteArray QXmppUtils::generateHmacMd5(const QByteArray &key, const QByteArray &text) { return generateHmac(QCryptographicHash::Md5, key, text); } /// Generates the SHA1 HMAC for the given \a key and \a text. QByteArray QXmppUtils::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 QXmppUtils::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 QXmppUtils::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 QXmppUtils::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 helperToXmlAddTextElement(QXmlStreamWriter* stream, const QString& name, const QString& value) { if(!value.isEmpty()) stream->writeTextElement( name, value); else stream->writeEmptyElement(name); } qxmpp-0.9.3/src/base/QXmppUtils.h000066400000000000000000000045331263006255200166360ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 #include "QXmppGlobal.h" class QByteArray; class QDateTime; class QDomElement; class QString; class QStringList; /// \brief The QXmppUtils class contains static utility functions. /// class QXMPP_EXPORT QXmppUtils { public: // XEP-0082: XMPP Date and Time Profiles static QDateTime datetimeFromString(const QString &str); static QString datetimeToString(const QDateTime &dt); static int timezoneOffsetFromString(const QString &str); static QString timezoneOffsetToString(int secs); static QString jidToDomain(const QString& jid); static QString jidToResource(const QString& jid); static QString jidToUser(const QString& jid); static QString jidToBareJid(const QString& jid); static quint32 generateCrc32(const QByteArray &input); static QByteArray generateHmacMd5(const QByteArray &key, const QByteArray &text); static QByteArray generateHmacSha1(const QByteArray &key, const QByteArray &text); static int generateRandomInteger(int N); static QByteArray generateRandomBytes(int length); static QString generateStanzaHash(int length=32); }; void helperToXmlAddAttribute(QXmlStreamWriter* stream, const QString& name, const QString& value); void helperToXmlAddTextElement(QXmlStreamWriter* stream, const QString& name, const QString& value); #endif // QXMPPUTILS_H qxmpp-0.9.3/src/base/QXmppVCardIq.cpp000066400000000000000000000620371263006255200173650ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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" static 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("country; } /// Sets the country. void QXmppVCardAddress::setCountry(const QString &country) { d->country = country; } /// Returns the locality. QString QXmppVCardAddress::locality() const { return d->locality; } /// Sets the locality. void QXmppVCardAddress::setLocality(const QString &locality) { d->locality = locality; } /// Returns the postcode. QString QXmppVCardAddress::postcode() const { return d->postcode; } /// Sets the postcode. void QXmppVCardAddress::setPostcode(const QString &postcode) { d->postcode = postcode; } /// Returns the region. QString QXmppVCardAddress::region() const { return d->region; } /// Sets the region. void QXmppVCardAddress::setRegion(const QString ®ion) { d->region = region; } /// Returns the street address. QString QXmppVCardAddress::street() const { return d->street; } /// Sets the street address. void QXmppVCardAddress::setStreet(const QString &street) { d->street = street; } /// Returns the address type, which is a combination of TypeFlag. QXmppVCardAddress::Type QXmppVCardAddress::type() const { return d->type; } /// Sets the address \a type, which is a combination of TypeFlag. void QXmppVCardAddress::setType(QXmppVCardAddress::Type type) { d->type = type; } /// \cond void QXmppVCardAddress::parse(const QDomElement &element) { if (!element.firstChildElement("HOME").isNull()) d->type |= Home; if (!element.firstChildElement("WORK").isNull()) d->type |= Work; if (!element.firstChildElement("POSTAL").isNull()) d->type |= Postal; if (!element.firstChildElement("PREF").isNull()) d->type |= Preferred; d->country = element.firstChildElement("CTRY").text(); d->locality = element.firstChildElement("LOCALITY").text(); d->postcode = element.firstChildElement("PCODE").text(); d->region = element.firstChildElement("REGION").text(); d->street = element.firstChildElement("STREET").text(); } void QXmppVCardAddress::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement("ADR"); if (d->type & Home) writer->writeEmptyElement("HOME"); if (d->type & Work) writer->writeEmptyElement("WORK"); if (d->type & Postal) writer->writeEmptyElement("POSTAL"); if (d->type & Preferred) writer->writeEmptyElement("PREF"); if (!d->country.isEmpty()) writer->writeTextElement("CTRY", d->country); if (!d->locality.isEmpty()) writer->writeTextElement("LOCALITY", d->locality); if (!d->postcode.isEmpty()) writer->writeTextElement("PCODE", d->postcode); if (!d->region.isEmpty()) writer->writeTextElement("REGION", d->region); if (!d->street.isEmpty()) writer->writeTextElement("STREET", d->street); writer->writeEndElement(); } /// \endcond class QXmppVCardEmailPrivate : public QSharedData { public: QXmppVCardEmailPrivate() : type(QXmppVCardEmail::None) {}; QString address; QXmppVCardEmail::Type type; }; /// Constructs an empty e-mail address. QXmppVCardEmail::QXmppVCardEmail() : d(new QXmppVCardEmailPrivate) { } /// Constructs a copy of \a other. QXmppVCardEmail::QXmppVCardEmail(const QXmppVCardEmail &other) : d(other.d) { } QXmppVCardEmail::~QXmppVCardEmail() { } /// Assigns \a other to this e-mail address. QXmppVCardEmail& QXmppVCardEmail::operator=(const QXmppVCardEmail &other) { d = other.d; return *this; } /// \brief Checks if two email objects represent the same email address. bool operator==(const QXmppVCardEmail &left, const QXmppVCardEmail &right) { return left.type() == right.type() && left.address() == right.address(); } /// \brief Checks if two email objects represent different email addresses. bool operator!=(const QXmppVCardEmail &left, const QXmppVCardEmail &right) { return !(left == right); } /// Returns the e-mail address. QString QXmppVCardEmail::address() const { return d->address; } /// Sets the e-mail \a address. void QXmppVCardEmail::setAddress(const QString &address) { d->address = address; } /// Returns the e-mail type, which is a combination of TypeFlag. QXmppVCardEmail::Type QXmppVCardEmail::type() const { return d->type; } /// Sets the e-mail \a type, which is a combination of TypeFlag. void QXmppVCardEmail::setType(QXmppVCardEmail::Type type) { d->type = type; } /// \cond void QXmppVCardEmail::parse(const QDomElement &element) { if (!element.firstChildElement("HOME").isNull()) d->type |= Home; if (!element.firstChildElement("WORK").isNull()) d->type |= Work; if (!element.firstChildElement("INTERNET").isNull()) d->type |= Internet; if (!element.firstChildElement("PREF").isNull()) d->type |= Preferred; if (!element.firstChildElement("X400").isNull()) d->type |= X400; d->address = element.firstChildElement("USERID").text(); } void QXmppVCardEmail::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement("EMAIL"); if (d->type & Home) writer->writeEmptyElement("HOME"); if (d->type & Work) writer->writeEmptyElement("WORK"); if (d->type & Internet) writer->writeEmptyElement("INTERNET"); if (d->type & Preferred) writer->writeEmptyElement("PREF"); if (d->type & X400) writer->writeEmptyElement("X400"); writer->writeTextElement("USERID", d->address); writer->writeEndElement(); } /// \endcond class QXmppVCardPhonePrivate : public QSharedData { public: QXmppVCardPhonePrivate() : type(QXmppVCardPhone::None) {}; QString number; QXmppVCardPhone::Type type; }; /// Constructs an empty phone number. QXmppVCardPhone::QXmppVCardPhone() : d(new QXmppVCardPhonePrivate) { } /// Constructs a copy of \a other. QXmppVCardPhone::QXmppVCardPhone(const QXmppVCardPhone &other) : d(other.d) { } QXmppVCardPhone::~QXmppVCardPhone() { } /// Assigns \a other to this phone number. QXmppVCardPhone& QXmppVCardPhone::operator=(const QXmppVCardPhone &other) { d = other.d; return *this; } /// Returns the phone number. QString QXmppVCardPhone::number() const { return d->number; } /// \brief Checks if two phone objects represent the same phone number. bool operator==(const QXmppVCardPhone &left, const QXmppVCardPhone &right) { return left.type() == right.type() && left.number() == right.number(); } /// \brief Checks if two phone objects represent different phone numbers. bool operator!=(const QXmppVCardPhone &left, const QXmppVCardPhone &right) { return !(left == right); } /// Sets the phone \a number. void QXmppVCardPhone::setNumber(const QString &number) { d->number = number; } /// Returns the phone number type, which is a combination of TypeFlag. QXmppVCardPhone::Type QXmppVCardPhone::type() const { return d->type; } /// Sets the phone number \a type, which is a combination of TypeFlag. void QXmppVCardPhone::setType(QXmppVCardPhone::Type type) { d->type = type; } /// \cond void QXmppVCardPhone::parse(const QDomElement &element) { if (!element.firstChildElement("HOME").isNull()) d->type |= Home; if (!element.firstChildElement("WORK").isNull()) d->type |= Work; if (!element.firstChildElement("VOICE").isNull()) d->type |= Voice; if (!element.firstChildElement("FAX").isNull()) d->type |= Fax; if (!element.firstChildElement("PAGER").isNull()) d->type |= Pager; if (!element.firstChildElement("MSG").isNull()) d->type |= Messaging; if (!element.firstChildElement("CELL").isNull()) d->type |= Cell; if (!element.firstChildElement("VIDEO").isNull()) d->type |= Video; if (!element.firstChildElement("BBS").isNull()) d->type |= BBS; if (!element.firstChildElement("MODEM").isNull()) d->type |= Modem; if (!element.firstChildElement("ISDN").isNull()) d->type |= ISDN; if (!element.firstChildElement("PCS").isNull()) d->type |= PCS; if (!element.firstChildElement("PREF").isNull()) d->type |= Preferred; d->number = element.firstChildElement("NUMBER").text(); } void QXmppVCardPhone::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement("TEL"); if (d->type & Home) writer->writeEmptyElement("HOME"); if (d->type & Work) writer->writeEmptyElement("WORK"); if (d->type & Voice) writer->writeEmptyElement("VOICE"); if (d->type & Fax) writer->writeEmptyElement("FAX"); if (d->type & Pager) writer->writeEmptyElement("PAGER"); if (d->type & Messaging) writer->writeEmptyElement("MSG"); if (d->type & Cell) writer->writeEmptyElement("CELL"); if (d->type & Video) writer->writeEmptyElement("VIDEO"); if (d->type & BBS) writer->writeEmptyElement("BBS"); if (d->type & Modem) writer->writeEmptyElement("MODEM"); if (d->type & ISDN) writer->writeEmptyElement("ISDN"); if (d->type & PCS) writer->writeEmptyElement("PCS"); if (d->type & Preferred) writer->writeEmptyElement("PREF"); writer->writeTextElement("NUMBER", d->number); writer->writeEndElement(); } /// \endcond class QXmppVCardOrganizationPrivate : public QSharedData { public: QString organization; QString unit; QString role; QString title; }; /// Constructs an empty organization information. QXmppVCardOrganization::QXmppVCardOrganization() : d(new QXmppVCardOrganizationPrivate) { } /// Constructs a copy of \a other. QXmppVCardOrganization::QXmppVCardOrganization(const QXmppVCardOrganization &other) : d(other.d) { } QXmppVCardOrganization::~QXmppVCardOrganization() { } /// Assigns \a other to this organization info. QXmppVCardOrganization& QXmppVCardOrganization::operator=(const QXmppVCardOrganization &other) { d = other.d; return *this; } /// \brief Checks if two organization objects represent the same organization. bool operator==(const QXmppVCardOrganization &left, const QXmppVCardOrganization &right) { return left.organization() == right.organization() && left.unit() == right.unit() && left.title() == right.title() && left.role() == right.role(); } /// \brief Checks if two organization objects represent different organizations. bool operator!=(const QXmppVCardOrganization &left, const QXmppVCardOrganization &right) { return !(left == right); } /// Returns the name of the organization. QString QXmppVCardOrganization::organization() const { return d->organization; } /// Sets the organization \a name. void QXmppVCardOrganization::setOrganization(const QString &name) { d->organization = name; } /// Returns the organization unit (also known as department). QString QXmppVCardOrganization::unit() const { return d->unit; } /// Sets the \a unit within the organization. void QXmppVCardOrganization::setUnit(const QString &unit) { d->unit = unit; } /// Returns the job role within the organization. QString QXmppVCardOrganization::role() const { return d->role; } /// Sets the job \a role within the organization. void QXmppVCardOrganization::setRole(const QString &role) { d->role = role; } /// Returns the job title within the organization. QString QXmppVCardOrganization::title() const { return d->title; } /// Sets the job \a title within the organization. void QXmppVCardOrganization::setTitle(const QString &title) { d->title = title; } /// \cond void QXmppVCardOrganization::parse(const QDomElement &cardElem) { d->title = cardElem.firstChildElement("TITLE").text(); d->role = cardElem.firstChildElement("ROLE").text(); const QDomElement &orgElem = cardElem.firstChildElement("ORG"); d->organization = orgElem.firstChildElement("ORGNAME").text(); d->unit = orgElem.firstChildElement("ORGUNIT").text(); } void QXmppVCardOrganization::toXml(QXmlStreamWriter *stream) const { if (!d->unit.isEmpty() || !d->organization.isEmpty()) { stream->writeStartElement("ORG"); stream->writeTextElement("ORGNAME", d->organization); stream->writeTextElement("ORGUNIT", d->unit); stream->writeEndElement(); } helperToXmlAddTextElement(stream, "TITLE", d->title); helperToXmlAddTextElement(stream, "ROLE", d->role); } /// \endcond class QXmppVCardIqPrivate : public QSharedData { public: QDate birthday; QString description; QString firstName; QString fullName; QString lastName; QString middleName; QString nickName; QString url; // not as 64 base QByteArray photo; QString photoType; QList addresses; QList emails; QList phones; QXmppVCardOrganization organization; }; /// Constructs a QXmppVCardIq for the specified recipient. /// /// \param jid QXmppVCardIq::QXmppVCardIq(const QString& jid) : QXmppIq() , d(new QXmppVCardIqPrivate) { // for self jid should be empty setTo(jid); } /// Constructs a copy of \a other. QXmppVCardIq::QXmppVCardIq(const QXmppVCardIq &other) : QXmppIq(other) , d(other.d) { } QXmppVCardIq::~QXmppVCardIq() { } /// Assigns \a other to this vCard IQ. QXmppVCardIq& QXmppVCardIq::operator=(const QXmppVCardIq &other) { QXmppIq::operator=(other); d = other.d; return *this; } /// \brief Checks if two VCard objects represent the same VCard. bool operator==(const QXmppVCardIq &left, const QXmppVCardIq &right) { return left.birthday() == right.birthday() && left.description() == right.description() && left.email() == right.email() && left.firstName() == right.firstName() && left.fullName() == right.fullName() && left.lastName() == right.lastName() && left.middleName() == right.middleName() && left.nickName() == right.nickName() && left.photo() == right.photo() && left.photoType() == right.photoType() && left.url() == right.url() && left.addresses() == right.addresses() && left.emails() == right.emails() && left.phones() == right.phones() && left.organization() == right.organization(); } /// \brief Checks if two VCard objects represent different VCards. bool operator!=(const QXmppVCardIq &left, const QXmppVCardIq &right) { return !(left == right); } /// Returns the date of birth of the individual associated with the vCard. /// QDate QXmppVCardIq::birthday() const { return d->birthday; } /// Sets the date of birth of the individual associated with the vCard. /// /// \param birthday void QXmppVCardIq::setBirthday(const QDate &birthday) { d->birthday = birthday; } /// Returns the free-form descriptive text. QString QXmppVCardIq::description() const { return d->description; } /// Sets the free-form descriptive text. void QXmppVCardIq::setDescription(const QString &description) { d->description = description; } /// Returns the email address. /// QString QXmppVCardIq::email() const { if (d->emails.isEmpty()) return QString(); else return d->emails.first().address(); } /// Sets the email address. /// /// \param email void QXmppVCardIq::setEmail(const QString &email) { QXmppVCardEmail first; first.setAddress(email); first.setType(QXmppVCardEmail::Internet); d->emails = QList() << first; } /// Returns the first name. /// QString QXmppVCardIq::firstName() const { return d->firstName; } /// Sets the first name. /// /// \param firstName void QXmppVCardIq::setFirstName(const QString &firstName) { d->firstName = firstName; } /// Returns the full name. /// QString QXmppVCardIq::fullName() const { return d->fullName; } /// Sets the full name. /// /// \param fullName void QXmppVCardIq::setFullName(const QString &fullName) { d->fullName = fullName; } /// Returns the last name. /// QString QXmppVCardIq::lastName() const { return d->lastName; } /// Sets the last name. /// /// \param lastName void QXmppVCardIq::setLastName(const QString &lastName) { d->lastName = lastName; } /// Returns the middle name. /// QString QXmppVCardIq::middleName() const { return d->middleName; } /// Sets the middle name. /// /// \param middleName void QXmppVCardIq::setMiddleName(const QString &middleName) { d->middleName = middleName; } /// Returns the nickname. /// QString QXmppVCardIq::nickName() const { return d->nickName; } /// Sets the nickname. /// /// \param nickName void QXmppVCardIq::setNickName(const QString &nickName) { d->nickName = nickName; } /// Returns the URL associated with the vCard. It can represent the user's /// homepage or a location at which you can find real-time information about /// the vCard. QString QXmppVCardIq::url() const { return d->url; } /// Sets the URL associated with the vCard. It can represent the user's /// homepage or a location at which you can find real-time information about /// the vCard. /// /// \param url void QXmppVCardIq::setUrl(const QString& url) { d->url = url; } /// Returns the photo's binary contents. /// /// If you want to use the photo as a QImage you can use: /// /// \code /// QBuffer buffer; /// buffer.setData(myCard.photo()); /// buffer.open(QIODevice::ReadOnly); /// QImageReader imageReader(&buffer); /// QImage myImage = imageReader.read(); /// \endcode QByteArray QXmppVCardIq::photo() const { return d->photo; } /// Sets the photo's binary contents. void QXmppVCardIq::setPhoto(const QByteArray& photo) { d->photo = photo; } /// Returns the photo's MIME type. QString QXmppVCardIq::photoType() const { return d->photoType; } /// Sets the photo's MIME type. void QXmppVCardIq::setPhotoType(const QString& photoType) { d->photoType = photoType; } /// Returns the addresses. QList QXmppVCardIq::addresses() const { return d->addresses; } /// Sets the addresses. void QXmppVCardIq::setAddresses(const QList &addresses) { d->addresses = addresses; } /// Returns the e-mail addresses. QList QXmppVCardIq::emails() const { return d->emails; } /// Sets the e-mail addresses. void QXmppVCardIq::setEmails(const QList &emails) { d->emails = emails; } /// Returns the phone numbers. QList QXmppVCardIq::phones() const { return d->phones; } /// Sets the phone numbers. void QXmppVCardIq::setPhones(const QList &phones) { d->phones = phones; } /// Returns the organization info. QXmppVCardOrganization QXmppVCardIq::organization() const { return d->organization; } /// Sets the organization info. void QXmppVCardIq::setOrganization(const QXmppVCardOrganization &org) { d->organization = org; } /// \cond bool QXmppVCardIq::isVCard(const QDomElement &nodeRecv) { return nodeRecv.firstChildElement("vCard").namespaceURI() == ns_vcard; } void QXmppVCardIq::parseElementFromChild(const QDomElement& nodeRecv) { // vCard QDomElement cardElement = nodeRecv.firstChildElement("vCard"); d->birthday = QDate::fromString(cardElement.firstChildElement("BDAY").text(), "yyyy-MM-dd"); d->description = cardElement.firstChildElement("DESC").text(); d->fullName = cardElement.firstChildElement("FN").text(); d->nickName = cardElement.firstChildElement("NICKNAME").text(); QDomElement nameElement = cardElement.firstChildElement("N"); d->firstName = nameElement.firstChildElement("GIVEN").text(); d->lastName = nameElement.firstChildElement("FAMILY").text(); d->middleName = nameElement.firstChildElement("MIDDLE").text(); d->url = cardElement.firstChildElement("URL").text(); QDomElement photoElement = cardElement.firstChildElement("PHOTO"); QByteArray base64data = photoElement. firstChildElement("BINVAL").text().toLatin1(); d->photo = QByteArray::fromBase64(base64data); d->photoType = photoElement.firstChildElement("TYPE").text(); QDomElement child = cardElement.firstChildElement(); while (!child.isNull()) { if (child.tagName() == "ADR") { QXmppVCardAddress address; address.parse(child); d->addresses << address; } else if (child.tagName() == "EMAIL") { QXmppVCardEmail email; email.parse(child); d->emails << email; } else if (child.tagName() == "TEL") { QXmppVCardPhone phone; phone.parse(child); d->phones << phone; } child = child.nextSiblingElement(); } d->organization.parse(cardElement); } void QXmppVCardIq::toXmlElementFromChild(QXmlStreamWriter *writer) const { writer->writeStartElement("vCard"); writer->writeAttribute("xmlns", ns_vcard); foreach (const QXmppVCardAddress &address, d->addresses) address.toXml(writer); if (d->birthday.isValid()) helperToXmlAddTextElement(writer, "BDAY", d->birthday.toString("yyyy-MM-dd")); if (!d->description.isEmpty()) helperToXmlAddTextElement(writer, "DESC", d->description); foreach (const QXmppVCardEmail &email, d->emails) email.toXml(writer); if (!d->fullName.isEmpty()) helperToXmlAddTextElement(writer, "FN", d->fullName); if(!d->nickName.isEmpty()) helperToXmlAddTextElement(writer, "NICKNAME", d->nickName); if (!d->firstName.isEmpty() || !d->lastName.isEmpty() || !d->middleName.isEmpty()) { writer->writeStartElement("N"); if (!d->firstName.isEmpty()) helperToXmlAddTextElement(writer, "GIVEN", d->firstName); if (!d->lastName.isEmpty()) helperToXmlAddTextElement(writer, "FAMILY", d->lastName); if (!d->middleName.isEmpty()) helperToXmlAddTextElement(writer, "MIDDLE", d->middleName); writer->writeEndElement(); } foreach (const QXmppVCardPhone &phone, d->phones) phone.toXml(writer); if(!photo().isEmpty()) { writer->writeStartElement("PHOTO"); QString photoType = d->photoType; if (photoType.isEmpty()) photoType = getImageType(d->photo); helperToXmlAddTextElement(writer, "TYPE", photoType); helperToXmlAddTextElement(writer, "BINVAL", d->photo.toBase64()); writer->writeEndElement(); } if (!d->url.isEmpty()) helperToXmlAddTextElement(writer, "URL", d->url); d->organization.toXml(writer); writer->writeEndElement(); } /// \endcond qxmpp-0.9.3/src/base/QXmppVCardIq.h000066400000000000000000000172321263006255200170270ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 QXmppVCardAddressPrivate; class QXmppVCardEmailPrivate; class QXmppVCardPhonePrivate; class QXmppVCardOrganizationPrivate; class QXmppVCardIqPrivate; /// \brief Represent a vCard address. class QXMPP_EXPORT QXmppVCardAddress { public: /// \brief Describes e-mail address types. enum TypeFlag { None = 0x0, Home = 0x1, Work = 0x2, Postal = 0x4, Preferred = 0x8 }; Q_DECLARE_FLAGS(Type, TypeFlag) QXmppVCardAddress(); QXmppVCardAddress(const QXmppVCardAddress &other); ~QXmppVCardAddress(); QXmppVCardAddress& operator=(const QXmppVCardAddress &other); QString country() const; void setCountry(const QString &country); QString locality() const; void setLocality(const QString &locality); QString postcode() const; void setPostcode(const QString &postcode); QString region() const; void setRegion(const QString ®ion); QString street() const; void setStreet(const QString &street); Type type() const; void setType(Type type); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *stream) const; /// \endcond private: QSharedDataPointer d; }; QXMPP_EXPORT bool operator==(const QXmppVCardAddress&, const QXmppVCardAddress&); QXMPP_EXPORT bool operator!=(const QXmppVCardAddress&, const QXmppVCardAddress&); /// \brief Represents a vCard e-mail address. class QXMPP_EXPORT QXmppVCardEmail { public: /// \brief Describes e-mail address types. enum TypeFlag { None = 0x0, Home = 0x1, Work = 0x2, Internet = 0x4, Preferred = 0x8, X400 = 0x10 }; Q_DECLARE_FLAGS(Type, TypeFlag) QXmppVCardEmail(); QXmppVCardEmail(const QXmppVCardEmail &other); ~QXmppVCardEmail(); QXmppVCardEmail& operator=(const QXmppVCardEmail &other); QString address() const; void setAddress(const QString &address); Type type() const; void setType(Type type); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *stream) const; /// \endcond private: QSharedDataPointer d; }; QXMPP_EXPORT bool operator==(const QXmppVCardEmail&, const QXmppVCardEmail&); QXMPP_EXPORT bool operator!=(const QXmppVCardEmail&, const QXmppVCardEmail&); /// \brief Represents a vCard phone number. class QXMPP_EXPORT QXmppVCardPhone { public: /// \brief Describes phone number types. enum TypeFlag { None = 0x0, Home = 0x1, Work = 0x2, Voice = 0x4, Fax = 0x8, Pager = 0x10, Messaging = 0x20, Cell = 0x40, Video = 0x80, BBS = 0x100, Modem = 0x200, ISDN = 0x400, PCS = 0x800, Preferred = 0x1000 }; Q_DECLARE_FLAGS(Type, TypeFlag) QXmppVCardPhone(); QXmppVCardPhone(const QXmppVCardPhone &other); ~QXmppVCardPhone(); QXmppVCardPhone& operator=(const QXmppVCardPhone &other); QString number() const; void setNumber(const QString &number); Type type() const; void setType(Type type); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *stream) const; /// \endcond private: QSharedDataPointer d; }; QXMPP_EXPORT bool operator==(const QXmppVCardPhone&, const QXmppVCardPhone&); QXMPP_EXPORT bool operator!=(const QXmppVCardPhone&, const QXmppVCardPhone&); /// \brief Represents organization information in XMPP vCards. /// /// This contains both information about organization itself and /// information about job position in the organization. class QXMPP_EXPORT QXmppVCardOrganization { public: QXmppVCardOrganization(); QXmppVCardOrganization(const QXmppVCardOrganization &other); ~QXmppVCardOrganization(); QXmppVCardOrganization& operator=(const QXmppVCardOrganization &other); QString organization() const; void setOrganization(const QString&); QString unit() const; void setUnit(const QString&); QString title() const; void setTitle(const QString&); QString role() const; void setRole(const QString&); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *stream) const; /// \endcond private: QSharedDataPointer d; }; QXMPP_EXPORT bool operator==(const QXmppVCardOrganization&, const QXmppVCardOrganization&); QXMPP_EXPORT bool operator!=(const QXmppVCardOrganization&, const QXmppVCardOrganization&); /// \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 QXMPP_EXPORT QXmppVCardIq : public QXmppIq { public: QXmppVCardIq(const QString& bareJid = QString()); QXmppVCardIq(const QXmppVCardIq &other); ~QXmppVCardIq(); QXmppVCardIq& operator=(const QXmppVCardIq &other); QDate birthday() const; void setBirthday(const QDate &birthday); QString description() const; void setDescription(const QString &description); 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&); QList addresses() const; void setAddresses(const QList &addresses); QList emails() const; void setEmails(const QList &emails); QList phones() const; void setPhones(const QList &phones); QXmppVCardOrganization organization() const; void setOrganization(const QXmppVCardOrganization&); /// \cond static bool isVCard(const QDomElement &element); /// \endcond protected: /// \cond void parseElementFromChild(const QDomElement&); void toXmlElementFromChild(QXmlStreamWriter *writer) const; /// \endcond private: QSharedDataPointer d; }; QXMPP_EXPORT bool operator==(const QXmppVCardIq&, const QXmppVCardIq&); QXMPP_EXPORT bool operator!=(const QXmppVCardIq&, const QXmppVCardIq&); #endif // QXMPPVCARDIQ_H qxmpp-0.9.3/src/base/QXmppVersionIq.cpp000066400000000000000000000047151263006255200200120ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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; } /// \cond 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(); } /// \endcond qxmpp-0.9.3/src/base/QXmppVersionIq.h000066400000000000000000000030061263006255200174470ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPP_EXPORT 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 qxmpp-0.9.3/src/base/base.pri000066400000000000000000000052101263006255200160160ustar00rootroot00000000000000# Header files INSTALL_HEADERS += \ base/QXmppArchiveIq.h \ base/QXmppBindIq.h \ base/QXmppBookmarkSet.h \ base/QXmppByteStreamIq.h \ base/QXmppConstants.h \ base/QXmppDataForm.h \ base/QXmppDiscoveryIq.h \ base/QXmppElement.h \ base/QXmppEntityTimeIq.h \ base/QXmppGlobal.h \ base/QXmppIbbIq.h \ base/QXmppIq.h \ base/QXmppJingleIq.h \ base/QXmppLogger.h \ base/QXmppMessage.h \ base/QXmppMucIq.h \ base/QXmppNonSASLAuth.h \ base/QXmppPingIq.h \ base/QXmppPresence.h \ base/QXmppPubSubIq.h \ base/QXmppRegisterIq.h \ base/QXmppResultSet.h \ base/QXmppRosterIq.h \ base/QXmppRpcIq.h \ base/QXmppRtcpPacket.h \ base/QXmppRtpChannel.h \ base/QXmppRtpPacket.h \ base/QXmppSessionIq.h \ base/QXmppSocks.h \ base/QXmppStanza.h \ base/QXmppStream.h \ base/QXmppStreamFeatures.h \ base/QXmppStun.h \ base/QXmppUtils.h \ base/QXmppVCardIq.h \ base/QXmppVersionIq.h HEADERS += \ base/QXmppCodec_p.h \ base/QXmppSasl_p.h \ base/QXmppStreamInitiationIq_p.h \ base/QXmppStun_p.h # Source files SOURCES += \ base/QXmppArchiveIq.cpp \ base/QXmppBindIq.cpp \ base/QXmppBookmarkSet.cpp \ base/QXmppByteStreamIq.cpp \ base/QXmppCodec.cpp \ base/QXmppConstants.cpp \ base/QXmppDataForm.cpp \ base/QXmppDiscoveryIq.cpp \ base/QXmppElement.cpp \ base/QXmppEntityTimeIq.cpp \ base/QXmppGlobal.cpp \ base/QXmppIbbIq.cpp \ base/QXmppIq.cpp \ base/QXmppJingleIq.cpp \ base/QXmppLogger.cpp \ base/QXmppMessage.cpp \ base/QXmppMucIq.cpp \ base/QXmppNonSASLAuth.cpp \ base/QXmppPingIq.cpp \ base/QXmppPresence.cpp \ base/QXmppPubSubIq.cpp \ base/QXmppRegisterIq.cpp \ base/QXmppResultSet.cpp \ base/QXmppRosterIq.cpp \ base/QXmppRpcIq.cpp \ base/QXmppRtcpPacket.cpp \ base/QXmppRtpChannel.cpp \ base/QXmppRtpPacket.cpp \ base/QXmppSasl.cpp \ base/QXmppSessionIq.cpp \ base/QXmppSocks.cpp \ base/QXmppStanza.cpp \ base/QXmppStream.cpp \ base/QXmppStreamFeatures.cpp \ base/QXmppStreamInitiationIq.cpp \ base/QXmppStun.cpp \ base/QXmppUtils.cpp \ base/QXmppVCardIq.cpp \ base/QXmppVersionIq.cpp # DNS qt_version = $$QT_MAJOR_VERSION contains(qt_version, 4) { INSTALL_HEADERS += base/qdnslookup.h base/qdnslookup_p.h SOURCES += base/qdnslookup.cpp android:SOURCES += base/qdnslookup_stub.cpp else:symbian:SOURCES += base/qdnslookup_symbian.cpp else:unix:SOURCES += base/qdnslookup_unix.cpp else:win32:SOURCES += base/qdnslookup_win.cpp else:SOURCES += base/qdnslookup_stub.cpp } qxmpp-0.9.3/src/base/qdnslookup.cpp000066400000000000000000000550101263006255200172760ustar00rootroot00000000000000/**************************************************************************** ** ** 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 qxmpp-0.9.3/src/base/qdnslookup.h000066400000000000000000000142501263006255200167440ustar00rootroot00000000000000/**************************************************************************** ** ** 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 #include "QXmppGlobal.h" QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Network) class QHostAddress; class QDnsLookupPrivate; class QDnsDomainNameRecordPrivate; class QDnsHostAddressRecordPrivate; class QDnsMailExchangeRecordPrivate; class QDnsServiceRecordPrivate; class QDnsTextRecordPrivate; class QXMPP_EXPORT 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 QXMPP_EXPORT 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 QXMPP_EXPORT 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 QXMPP_EXPORT 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 QXMPP_EXPORT 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 QXMPP_EXPORT 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 qxmpp-0.9.3/src/base/qdnslookup_p.h000066400000000000000000000115541263006255200172670ustar00rootroot00000000000000/**************************************************************************** ** ** 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 qxmpp-0.9.3/src/base/qdnslookup_stub.cpp000066400000000000000000000037771263006255200203500ustar00rootroot00000000000000/**************************************************************************** ** ** 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 qxmpp-0.9.3/src/base/qdnslookup_symbian.cpp000066400000000000000000000066131263006255200210250ustar00rootroot00000000000000/**************************************************************************** ** ** 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 qxmpp-0.9.3/src/base/qdnslookup_unix.cpp000066400000000000000000000301331263006255200203400ustar00rootroot00000000000000/**************************************************************************** ** ** 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 qxmpp-0.9.3/src/base/qdnslookup_win.cpp000066400000000000000000000137111263006255200201550ustar00rootroot00000000000000/**************************************************************************** ** ** 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 #include "qdnslookup_p.h" #include #include #include #include #include QT_BEGIN_NAMESPACE void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply) { // Perform DNS query. PDNS_RECORD dns_records = 0; const DNS_STATUS status = DnsQuery_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); } } DnsRecordListFree(dns_records, DnsFreeRecordList); } QT_END_NAMESPACE qxmpp-0.9.3/src/client/000077500000000000000000000000001263006255200147365ustar00rootroot00000000000000qxmpp-0.9.3/src/client/QXmppArchiveManager.cpp000066400000000000000000000111341263006255200213040ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppArchiveManager.h" #include "QXmppClient.h" #include "QXmppConstants.h" /// \cond QStringList QXmppArchiveManager::discoveryFeatures() const { // XEP-0036: Message Archiving return QStringList() << ns_archive; } bool QXmppArchiveManager::handleStanza(const QDomElement &element) { if (element.tagName() != "iq") return false; // XEP-0136: Message Archiving if(QXmppArchiveChatIq::isArchiveChatIq(element)) { QXmppArchiveChatIq archiveIq; archiveIq.parse(element); emit archiveChatReceived(archiveIq.chat(), archiveIq.resultSetReply()); return true; } else if(QXmppArchiveListIq::isArchiveListIq(element)) { QXmppArchiveListIq archiveIq; archiveIq.parse(element); emit archiveListReceived(archiveIq.chats(), archiveIq.resultSetReply()); return true; } else if(QXmppArchivePrefIq::isArchivePrefIq(element)) { // TODO: handle preference iq QXmppArchivePrefIq archiveIq; archiveIq.parse(element); return true; } return false; } /// \endcond /// Retrieves the list of available collections. Once the results are /// received, the archiveListReceived() signal will be emitted. /// /// \param jid JID you want conversations with. /// \param start Optional start time. /// \param end Optional end time. /// \param rsm Optional Result Set Management query /// void QXmppArchiveManager::listCollections(const QString& jid, const QDateTime& start, const QDateTime& end, const QXmppResultSetQuery &rsm) { QXmppArchiveListIq packet; packet.setResultSetQuery(rsm); packet.setWith(jid); packet.setStart(start); packet.setEnd(end); client()->sendPacket(packet); } /// \overload /// Retrieves the list of available collections. Once the results are /// received, the archiveListReceived() signal will be emitted. /// /// \param jid JID you want conversations with. /// \param start Start time. /// \param end End time. /// \param max Maximum number of collections to list. /// void QXmppArchiveManager::listCollections(const QString &jid, const QDateTime &start, const QDateTime &end, int max) { QXmppResultSetQuery rsm; rsm.setMax(max); listCollections(jid, start, end, rsm); } /// Removes the specified collection(s). /// /// \param jid The JID of the collection /// \param start Optional start time. /// \param end Optional end time. /// void QXmppArchiveManager::removeCollections(const QString &jid, const QDateTime &start, const QDateTime &end) { QXmppArchiveRemoveIq packet; packet.setType(QXmppIq::Set); packet.setWith(jid); packet.setStart(start); packet.setEnd(end); client()->sendPacket(packet); } /// Retrieves the specified collection. Once the results are received, /// the archiveChatReceived() will be emitted. /// /// \param jid The JID of the collection /// \param start The start time of the collection. /// \param rsm Optional Result Set Management query /// void QXmppArchiveManager::retrieveCollection(const QString &jid, const QDateTime &start, const QXmppResultSetQuery &rsm) { QXmppArchiveRetrieveIq packet; packet.setResultSetQuery(rsm); packet.setStart(start); packet.setWith(jid); client()->sendPacket(packet); } /// \overload /// Retrieves the specified collection. Once the results are received, /// the archiveChatReceived() will be emitted. /// /// \param jid The JID of the collection /// \param start The start time of the collection. /// \param max Maximum number of messages to retrieve. /// void QXmppArchiveManager::retrieveCollection(const QString &jid, const QDateTime &start, int max) { QXmppResultSetQuery rsm; rsm.setMax(max); retrieveCollection(jid, start, rsm); } #if 0 void QXmppArchiveManager::getPreferences() { QXmppArchivePrefIq packet; client()->sendPacket(packet); } #endif qxmpp-0.9.3/src/client/QXmppArchiveManager.h000066400000000000000000000053321263006255200207540ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPARCHIVEMANAGER_H #define QXMPPARCHIVEMANAGER_H #include #include "QXmppClientExtension.h" #include "QXmppResultSet.h" class QXmppArchiveChat; class QXmppArchiveChatIq; class QXmppArchiveListIq; class QXmppArchivePrefIq; /// \brief The QXmppArchiveManager class makes it possible to access message /// archives as defined by XEP-0136: Message Archiving. /// /// To make use of this manager, you need to instantiate it and load it into /// the QXmppClient instance as follows: /// /// \code /// QXmppArchiveManager *manager = new QXmppArchiveManager; /// client->addExtension(manager); /// \endcode /// /// \note Few servers support message archiving. Check if the server in use supports /// this XEP. /// /// \ingroup Managers class QXMPP_EXPORT QXmppArchiveManager : public QXmppClientExtension { Q_OBJECT public: void listCollections(const QString &jid, const QDateTime &start = QDateTime(), const QDateTime &end = QDateTime(), const QXmppResultSetQuery &rsm = QXmppResultSetQuery()); void listCollections(const QString &jid, const QDateTime &start, const QDateTime &end, int max); void removeCollections(const QString &jid, const QDateTime &start = QDateTime(), const QDateTime &end = QDateTime()); void retrieveCollection(const QString &jid, const QDateTime &start, const QXmppResultSetQuery &rsm = QXmppResultSetQuery()); void retrieveCollection(const QString &jid, const QDateTime &start, int max); /// \cond QStringList discoveryFeatures() const; bool handleStanza(const QDomElement &element); /// \endcond signals: /// This signal is emitted when archive list is received /// after calling listCollections() void archiveListReceived(const QList&, const QXmppResultSetReply &rsm = QXmppResultSetReply()); /// This signal is emitted when archive chat is received /// after calling retrieveCollection() void archiveChatReceived(const QXmppArchiveChat&, const QXmppResultSetReply &rsm = QXmppResultSetReply()); }; #endif qxmpp-0.9.3/src/client/QXmppBookmarkManager.cpp000066400000000000000000000122531263006255200214730ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppBookmarkManager.h" #include "QXmppBookmarkSet.h" #include "QXmppClient.h" #include "QXmppConstants.h" #include "QXmppIq.h" #include "QXmppUtils.h" // The QXmppPrivateStorageIq class represents an XML private storage IQ // as defined by XEP-0049: Private XML Storage. // // FIXME: currently, we only handle bookmarks class QXmppPrivateStorageIq : public QXmppIq { public: QXmppBookmarkSet bookmarks() const; void setBookmarks(const QXmppBookmarkSet &bookmark); static bool isPrivateStorageIq(const QDomElement &element); protected: void parseElementFromChild(const QDomElement &element); void toXmlElementFromChild(QXmlStreamWriter *writer) const; private: QXmppBookmarkSet m_bookmarks; }; QXmppBookmarkSet QXmppPrivateStorageIq::bookmarks() const { return m_bookmarks; } void QXmppPrivateStorageIq::setBookmarks(const QXmppBookmarkSet &bookmarks) { m_bookmarks = bookmarks; } bool QXmppPrivateStorageIq::isPrivateStorageIq(const QDomElement &element) { const QDomElement queryElement = element.firstChildElement("query"); return queryElement.namespaceURI() == ns_private && QXmppBookmarkSet::isBookmarkSet(queryElement.firstChildElement()); } void QXmppPrivateStorageIq::parseElementFromChild(const QDomElement &element) { const QDomElement queryElement = element.firstChildElement("query"); m_bookmarks.parse(queryElement.firstChildElement()); } void QXmppPrivateStorageIq::toXmlElementFromChild(QXmlStreamWriter *writer) const { writer->writeStartElement("query"); writer->writeAttribute("xmlns", ns_private); m_bookmarks.toXml(writer); writer->writeEndElement(); } class QXmppBookmarkManagerPrivate { public: QXmppBookmarkSet bookmarks; QXmppBookmarkSet pendingBookmarks; QString pendingId; bool bookmarksReceived; }; /// Constructs a new bookmark manager. /// QXmppBookmarkManager::QXmppBookmarkManager() : d(new QXmppBookmarkManagerPrivate) { d->bookmarksReceived = false; } /// Destroys a bookmark manager. /// QXmppBookmarkManager::~QXmppBookmarkManager() { delete d; } /// Returns true if the bookmarks have been received from the server, /// false otherwise. /// bool QXmppBookmarkManager::areBookmarksReceived() const { return d->bookmarksReceived; } /// Returns the bookmarks stored on the server. /// /// Before calling this method, check that the bookmarks /// have indeed been received by calling areBookmarksReceived(). /// QXmppBookmarkSet QXmppBookmarkManager::bookmarks() const { return d->bookmarks; } /// Stores the bookmarks on the server. /// /// \param bookmarks bool QXmppBookmarkManager::setBookmarks(const QXmppBookmarkSet &bookmarks) { QXmppPrivateStorageIq iq; iq.setType(QXmppIq::Set); iq.setBookmarks(bookmarks); if (!client()->sendPacket(iq)) return false; d->pendingBookmarks = bookmarks; d->pendingId = iq.id(); return true; } /// \cond void QXmppBookmarkManager::setClient(QXmppClient *client) { bool check; Q_UNUSED(check); QXmppClientExtension::setClient(client); check = connect(client, SIGNAL(connected()), this, SLOT(slotConnected())); Q_ASSERT(check); check = connect(client, SIGNAL(disconnected()), this, SLOT(slotDisconnected())); Q_ASSERT(check); } bool QXmppBookmarkManager::handleStanza(const QDomElement &stanza) { if (stanza.tagName() == "iq") { if (QXmppPrivateStorageIq::isPrivateStorageIq(stanza)) { QXmppPrivateStorageIq iq; iq.parse(stanza); if (iq.type() == QXmppIq::Result) { d->bookmarks = iq.bookmarks(); d->bookmarksReceived = true; emit bookmarksReceived(d->bookmarks); } return true; } else if (!d->pendingId.isEmpty() && stanza.attribute("id") == d->pendingId) { QXmppIq iq; iq.parse(stanza); if (iq.type() == QXmppIq::Result) { d->bookmarks = d->pendingBookmarks; emit bookmarksReceived(d->bookmarks); } d->pendingId = QString(); return true; } } return false; } /// \endcond void QXmppBookmarkManager::slotConnected() { QXmppPrivateStorageIq iq; iq.setType(QXmppIq::Get); client()->sendPacket(iq); } void QXmppBookmarkManager::slotDisconnected() { d->bookmarks = QXmppBookmarkSet(); d->bookmarksReceived = false; } qxmpp-0.9.3/src/client/QXmppBookmarkManager.h000066400000000000000000000033131263006255200211350ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPBOOKMARKMANAGER_H #define QXMPPBOOKMARKMANAGER_H #include #include "QXmppClientExtension.h" class QXmppBookmarkManagerPrivate; class QXmppBookmarkSet; /// \brief The QXmppBookmarkManager class allows you to store and retrieve /// bookmarks as defined by XEP-0048: Bookmarks. /// class QXMPP_EXPORT QXmppBookmarkManager : public QXmppClientExtension { Q_OBJECT public: QXmppBookmarkManager(); ~QXmppBookmarkManager(); bool areBookmarksReceived() const; QXmppBookmarkSet bookmarks() const; bool setBookmarks(const QXmppBookmarkSet &bookmarks); /// \cond bool handleStanza(const QDomElement &stanza); /// \endcond signals: /// This signal is emitted when bookmarks are received. void bookmarksReceived(const QXmppBookmarkSet &bookmarks); protected: /// \cond void setClient(QXmppClient* client); /// \endcond private slots: void slotConnected(); void slotDisconnected(); private: QXmppBookmarkManagerPrivate * const d; }; #endif qxmpp-0.9.3/src/client/QXmppCallManager.cpp000066400000000000000000000631141263006255200206030ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppCallManager.h" #include "QXmppClient.h" #include "QXmppConstants.h" #include "QXmppJingleIq.h" #include "QXmppRtpChannel.h" #include "QXmppStun.h" #include "QXmppUtils.h" static const int RTP_COMPONENT = 1; static const int RTCP_COMPONENT = 2; static const QLatin1String AUDIO_MEDIA("audio"); static const QLatin1String VIDEO_MEDIA("video"); class QXmppCallPrivate { public: class Stream { public: QXmppRtpChannel *channel; QXmppIceConnection *connection; QString creator; QString media; QString name; }; QXmppCallPrivate(QXmppCall *qq); Stream *createStream(const QString &media); Stream *findStreamByMedia(const QString &media); Stream *findStreamByName(const QString &name); QXmppJingleIq::Content localContent(QXmppCallPrivate::Stream *stream) const; void handleAck(const QXmppIq &iq); bool handleDescription(QXmppCallPrivate::Stream *stream, const QXmppJingleIq::Content &content); void handleRequest(const QXmppJingleIq &iq); bool handleTransport(QXmppCallPrivate::Stream *stream, const QXmppJingleIq::Content &content); void setState(QXmppCall::State state); bool sendAck(const QXmppJingleIq &iq); bool sendInvite(); bool sendRequest(const QXmppJingleIq &iq); void terminate(QXmppJingleIq::Reason::Type reasonType); QXmppCall::Direction direction; QString jid; QString ownJid; QXmppCallManager *manager; QList requests; QString sid; QXmppCall::State state; // Media streams bool sendVideo; QList streams; QIODevice::OpenMode audioMode; QIODevice::OpenMode videoMode; private: QXmppCall *q; }; class QXmppCallManagerPrivate { public: QXmppCallManagerPrivate(QXmppCallManager *qq); QXmppCall *findCall(const QString &sid) const; QXmppCall *findCall(const QString &sid, QXmppCall::Direction direction) const; QList calls; QHostAddress stunHost; quint16 stunPort; QHostAddress turnHost; quint16 turnPort; QString turnUser; QString turnPassword; private: QXmppCallManager *q; }; QXmppCallPrivate::QXmppCallPrivate(QXmppCall *qq) : manager(0), state(QXmppCall::ConnectingState), sendVideo(false), audioMode(QIODevice::NotOpen), videoMode(QIODevice::NotOpen), q(qq) { qRegisterMetaType(); } QXmppCallPrivate::Stream *QXmppCallPrivate::findStreamByMedia(const QString &media) { foreach (Stream *stream, streams) if (stream->media == media) return stream; return 0; } QXmppCallPrivate::Stream *QXmppCallPrivate::findStreamByName(const QString &name) { foreach (Stream *stream, streams) if (stream->name == name) return stream; return 0; } void QXmppCallPrivate::handleAck(const QXmppIq &ack) { const QString id = ack.id(); for (int i = 0; i < requests.size(); ++i) { if (id == requests[i].id()) { // process acknowledgement const QXmppJingleIq request = requests.takeAt(i); q->debug(QString("Received ACK for packet %1").arg(id)); // handle termination if (request.action() == QXmppJingleIq::SessionTerminate) q->terminated(); return; } } } bool QXmppCallPrivate::handleDescription(QXmppCallPrivate::Stream *stream, const QXmppJingleIq::Content &content) { stream->channel->setRemotePayloadTypes(content.payloadTypes()); if (!(stream->channel->openMode() & QIODevice::ReadWrite)) { q->warning(QString("Remote party %1 did not provide any known %2 payloads for call %3").arg(jid, stream->media, sid)); return false; } q->updateOpenMode(); return true; } bool QXmppCallPrivate::handleTransport(QXmppCallPrivate::Stream *stream, const QXmppJingleIq::Content &content) { stream->connection->setRemoteUser(content.transportUser()); stream->connection->setRemotePassword(content.transportPassword()); foreach (const QXmppJingleCandidate &candidate, content.transportCandidates()) stream->connection->addRemoteCandidate(candidate); // perform ICE negotiation if (!content.transportCandidates().isEmpty()) stream->connection->connectToHost(); return true; } void QXmppCallPrivate::handleRequest(const QXmppJingleIq &iq) { const QXmppJingleIq::Content content = iq.contents().isEmpty() ? QXmppJingleIq::Content() : iq.contents().first(); if (iq.action() == QXmppJingleIq::SessionAccept) { if (direction == QXmppCall::IncomingDirection) { q->warning("Ignoring Session-Accept for an incoming call"); return; } // send ack sendAck(iq); // check content description and transport QXmppCallPrivate::Stream *stream = findStreamByName(content.name()); if (!stream || !handleDescription(stream, content) || !handleTransport(stream, content)) { // terminate call terminate(QXmppJingleIq::Reason::FailedApplication); return; } // check for call establishment setState(QXmppCall::ActiveState); } else if (iq.action() == QXmppJingleIq::SessionInfo) { // notify user QTimer::singleShot(0, q, SIGNAL(ringing())); } else if (iq.action() == QXmppJingleIq::SessionTerminate) { // send ack sendAck(iq); // terminate q->info(QString("Remote party %1 terminated call %2").arg(iq.from(), iq.sid())); q->terminated(); } else if (iq.action() == QXmppJingleIq::ContentAccept) { // send ack sendAck(iq); // check content description and transport QXmppCallPrivate::Stream *stream = findStreamByName(content.name()); if (!stream || !handleDescription(stream, content) || !handleTransport(stream, content)) { // FIXME: what action? return; } } else if (iq.action() == QXmppJingleIq::ContentAdd) { // send ack sendAck(iq); // check media stream does not exist yet QXmppCallPrivate::Stream *stream = findStreamByName(content.name()); if (stream) return; // create media stream stream = createStream(content.descriptionMedia()); if (!stream) return; stream->creator = content.creator(); stream->name = content.name(); // check content description if (!handleDescription(stream, content) || !handleTransport(stream, content)) { QXmppJingleIq iq; iq.setTo(q->jid()); iq.setType(QXmppIq::Set); iq.setAction(QXmppJingleIq::ContentReject); iq.setSid(q->sid()); iq.reason().setType(QXmppJingleIq::Reason::FailedApplication); sendRequest(iq); delete stream; return; } streams << stream; // accept content QXmppJingleIq iq; iq.setTo(q->jid()); iq.setType(QXmppIq::Set); iq.setAction(QXmppJingleIq::ContentAccept); iq.setSid(q->sid()); iq.addContent(localContent(stream)); sendRequest(iq); } else if (iq.action() == QXmppJingleIq::TransportInfo) { // send ack sendAck(iq); // check content transport QXmppCallPrivate::Stream *stream = findStreamByName(content.name()); if (!stream || !handleTransport(stream, content)) { // FIXME: what action? return; } } } QXmppCallPrivate::Stream *QXmppCallPrivate::createStream(const QString &media) { bool check; Q_UNUSED(check); Q_ASSERT(manager); Stream *stream = new Stream; stream->media = media; // RTP channel QObject *channelObject = 0; if (media == AUDIO_MEDIA) { QXmppRtpAudioChannel *audioChannel = new QXmppRtpAudioChannel(q); stream->channel = audioChannel; channelObject = audioChannel; } else if (media == VIDEO_MEDIA) { QXmppRtpVideoChannel *videoChannel = new QXmppRtpVideoChannel(q); stream->channel = videoChannel; channelObject = videoChannel; } else { q->warning(QString("Unsupported media type %1").arg(media)); delete stream; return 0; } // ICE connection stream->connection = new QXmppIceConnection(q); stream->connection->setIceControlling(direction == QXmppCall::OutgoingDirection); stream->connection->setStunServer(manager->d->stunHost, manager->d->stunPort); stream->connection->setTurnServer(manager->d->turnHost, manager->d->turnPort); stream->connection->setTurnUser(manager->d->turnUser); stream->connection->setTurnPassword(manager->d->turnPassword); stream->connection->addComponent(RTP_COMPONENT); stream->connection->addComponent(RTCP_COMPONENT); stream->connection->bind(QXmppIceComponent::discoverAddresses()); // connect signals check = QObject::connect(stream->connection, SIGNAL(localCandidatesChanged()), q, SLOT(localCandidatesChanged())); Q_ASSERT(check); check = QObject::connect(stream->connection, SIGNAL(connected()), q, SLOT(updateOpenMode())); Q_ASSERT(check); check = QObject::connect(q, SIGNAL(stateChanged(QXmppCall::State)), q, SLOT(updateOpenMode())); Q_ASSERT(check); check = QObject::connect(stream->connection, SIGNAL(disconnected()), q, SLOT(hangup())); Q_ASSERT(check); if (channelObject) { QXmppIceComponent *rtpComponent = stream->connection->component(RTP_COMPONENT); check = QObject::connect(rtpComponent, SIGNAL(datagramReceived(QByteArray)), channelObject, SLOT(datagramReceived(QByteArray))); Q_ASSERT(check); check = QObject::connect(channelObject, SIGNAL(sendDatagram(QByteArray)), rtpComponent, SLOT(sendDatagram(QByteArray))); Q_ASSERT(check); } return stream; } QXmppJingleIq::Content QXmppCallPrivate::localContent(QXmppCallPrivate::Stream *stream) const { QXmppJingleIq::Content content; content.setCreator(stream->creator); content.setName(stream->name); content.setSenders("both"); // description content.setDescriptionMedia(stream->media); content.setDescriptionSsrc(stream->channel->localSsrc()); content.setPayloadTypes(stream->channel->localPayloadTypes()); // transport content.setTransportUser(stream->connection->localUser()); content.setTransportPassword(stream->connection->localPassword()); content.setTransportCandidates(stream->connection->localCandidates()); return content; } /// Sends an acknowledgement for a Jingle IQ. /// bool QXmppCallPrivate::sendAck(const QXmppJingleIq &iq) { QXmppIq ack; ack.setId(iq.id()); ack.setTo(iq.from()); ack.setType(QXmppIq::Result); return manager->client()->sendPacket(ack); } bool QXmppCallPrivate::sendInvite() { // create audio stream QXmppCallPrivate::Stream *stream = findStreamByMedia(AUDIO_MEDIA); Q_ASSERT(stream); QXmppJingleIq iq; iq.setTo(jid); iq.setType(QXmppIq::Set); iq.setAction(QXmppJingleIq::SessionInitiate); iq.setInitiator(ownJid); iq.setSid(sid); iq.addContent(localContent(stream)); return sendRequest(iq); } /// Sends a Jingle IQ and adds it to outstanding requests. /// bool QXmppCallPrivate::sendRequest(const QXmppJingleIq &iq) { requests << iq; return manager->client()->sendPacket(iq); } void QXmppCallPrivate::setState(QXmppCall::State newState) { if (state != newState) { state = newState; emit q->stateChanged(state); if (state == QXmppCall::ActiveState) emit q->connected(); else if (state == QXmppCall::FinishedState) emit q->finished(); } } /// Request graceful call termination void QXmppCallPrivate::terminate(QXmppJingleIq::Reason::Type reasonType) { if (state == QXmppCall::DisconnectingState || state == QXmppCall::FinishedState) return; // hangup call QXmppJingleIq iq; iq.setTo(jid); iq.setType(QXmppIq::Set); iq.setAction(QXmppJingleIq::SessionTerminate); iq.setSid(sid); iq.reason().setType(reasonType); sendRequest(iq); setState(QXmppCall::DisconnectingState); // schedule forceful termination in 5s QTimer::singleShot(5000, q, SLOT(terminated())); } QXmppCall::QXmppCall(const QString &jid, QXmppCall::Direction direction, QXmppCallManager *parent) : QXmppLoggable(parent) { d = new QXmppCallPrivate(this); d->direction = direction; d->jid = jid; d->ownJid = parent->client()->configuration().jid(); d->manager = parent; // create audio stream QXmppCallPrivate::Stream *stream = d->createStream(AUDIO_MEDIA); stream->creator = QLatin1String("initiator"); stream->name = QLatin1String("voice"); d->streams << stream; } QXmppCall::~QXmppCall() { foreach (QXmppCallPrivate::Stream *stream, d->streams) delete stream; delete d; } /// Call this method if you wish to accept an incoming call. /// void QXmppCall::accept() { if (d->direction == IncomingDirection && d->state == ConnectingState) { Q_ASSERT(d->streams.size() == 1); QXmppCallPrivate::Stream *stream = d->streams.first(); // accept incoming call QXmppJingleIq iq; iq.setTo(d->jid); iq.setType(QXmppIq::Set); iq.setAction(QXmppJingleIq::SessionAccept); iq.setResponder(d->ownJid); iq.setSid(d->sid); iq.addContent(d->localContent(stream)); d->sendRequest(iq); // notify user d->manager->callStarted(this); // check for call establishment d->setState(QXmppCall::ActiveState); } } /// Returns the RTP channel for the audio data. /// /// It acts as a QIODevice so that you can read / write audio samples, for /// instance using a QAudioOutput and a QAudioInput. /// QXmppRtpAudioChannel *QXmppCall::audioChannel() const { QXmppCallPrivate::Stream *stream = d->findStreamByMedia(AUDIO_MEDIA); if (stream) return static_cast(stream->channel); else return 0; } /// Returns the audio mode. QIODevice::OpenMode QXmppCall::audioMode() const { return d->audioMode; } /// Returns the RTP channel for the video data. /// QXmppRtpVideoChannel *QXmppCall::videoChannel() const { QXmppCallPrivate::Stream *stream = d->findStreamByMedia(VIDEO_MEDIA); if (stream) return static_cast(stream->channel); else return 0; } /// Returns the video mode. QIODevice::OpenMode QXmppCall::videoMode() const { return d->videoMode; } void QXmppCall::terminated() { // close streams foreach (QXmppCallPrivate::Stream *stream, d->streams) { stream->channel->close(); stream->connection->close(); } // update state d->setState(QXmppCall::FinishedState); } /// Returns the call's direction. /// QXmppCall::Direction QXmppCall::direction() const { return d->direction; } /// Hangs up the call. /// void QXmppCall::hangup() { d->terminate(QXmppJingleIq::Reason::None); } /// Sends a transport-info to inform the remote party of new local candidates. /// void QXmppCall::localCandidatesChanged() { // find the stream QXmppIceConnection *conn = qobject_cast(sender()); QXmppCallPrivate::Stream *stream = 0; foreach (QXmppCallPrivate::Stream *ptr, d->streams) { if (ptr->connection == conn) { stream = ptr; break; } } if (!stream) return; QXmppJingleIq iq; iq.setTo(d->jid); iq.setType(QXmppIq::Set); iq.setAction(QXmppJingleIq::TransportInfo); iq.setSid(d->sid); iq.addContent(d->localContent(stream)); d->sendRequest(iq); } /// Returns the remote party's JID. /// QString QXmppCall::jid() const { return d->jid; } void QXmppCall::updateOpenMode() { QXmppCallPrivate::Stream *stream; QIODevice::OpenMode mode; // determine audio mode mode = QIODevice::NotOpen; stream = d->findStreamByMedia(AUDIO_MEDIA); if (d->state == QXmppCall::ActiveState && stream && stream->connection->isConnected()) mode = stream->channel->openMode() & QIODevice::ReadWrite; if (mode != d->audioMode) { d->audioMode = mode; emit audioModeChanged(mode); } // determine video mode mode = QIODevice::NotOpen; stream = d->findStreamByMedia(VIDEO_MEDIA); if (d->state == QXmppCall::ActiveState && stream && stream->connection->isConnected()) { mode |= (stream->channel->openMode() & QIODevice::ReadOnly); if (d->sendVideo) mode |= (stream->channel->openMode() & QIODevice::WriteOnly); } if (mode != d->videoMode) { d->videoMode = mode; emit videoModeChanged(mode); } } /// Returns the call's session identifier. /// QString QXmppCall::sid() const { return d->sid; } /// Returns the call's state. /// /// \sa stateChanged() QXmppCall::State QXmppCall::state() const { return d->state; } /// Starts sending video to the remote party. void QXmppCall::startVideo() { if (d->state != QXmppCall::ActiveState) { warning("Cannot start video, call is not active"); return; } d->sendVideo = true; QXmppCallPrivate::Stream *stream = d->findStreamByMedia(VIDEO_MEDIA); if (stream) { updateOpenMode(); return; } // create video stream stream = d->createStream(VIDEO_MEDIA); stream->creator = (d->direction == QXmppCall::OutgoingDirection) ? QLatin1String("initiator") : QLatin1String("responder"); stream->name = QLatin1String("webcam"); d->streams << stream; // build request QXmppJingleIq iq; iq.setTo(d->jid); iq.setType(QXmppIq::Set); iq.setAction(QXmppJingleIq::ContentAdd); iq.setSid(d->sid); iq.addContent(d->localContent(stream)); d->sendRequest(iq); } /// Stops sending video to the remote party. void QXmppCall::stopVideo() { if (!d->sendVideo) return; d->sendVideo = false; QXmppCallPrivate::Stream *stream = d->findStreamByMedia(VIDEO_MEDIA); if (stream) updateOpenMode(); } QXmppCallManagerPrivate::QXmppCallManagerPrivate(QXmppCallManager *qq) : stunPort(0), turnPort(0), q(qq) { } QXmppCall *QXmppCallManagerPrivate::findCall(const QString &sid) const { foreach (QXmppCall *call, calls) if (call->sid() == sid) return call; return 0; } QXmppCall *QXmppCallManagerPrivate::findCall(const QString &sid, QXmppCall::Direction direction) const { foreach (QXmppCall *call, calls) if (call->sid() == sid && call->direction() == direction) return call; return 0; } /// Constructs a QXmppCallManager object to handle incoming and outgoing /// Voice-Over-IP calls. /// QXmppCallManager::QXmppCallManager() { d = new QXmppCallManagerPrivate(this); } /// Destroys the QXmppCallManager object. QXmppCallManager::~QXmppCallManager() { delete d; } /// \cond QStringList QXmppCallManager::discoveryFeatures() const { return QStringList() << ns_jingle // XEP-0166 : Jingle << ns_jingle_rtp // XEP-0167 : Jingle RTP Sessions << ns_jingle_rtp_audio << ns_jingle_rtp_video << ns_jingle_ice_udp; // XEP-0176 : Jingle ICE-UDP Transport Method } bool QXmppCallManager::handleStanza(const QDomElement &element) { if(element.tagName() == "iq") { // XEP-0166: Jingle if (QXmppJingleIq::isJingleIq(element)) { QXmppJingleIq jingleIq; jingleIq.parse(element); _q_jingleIqReceived(jingleIq); return true; } } return false; } void QXmppCallManager::setClient(QXmppClient *client) { bool check; Q_UNUSED(check); QXmppClientExtension::setClient(client); check = connect(client, SIGNAL(disconnected()), this, SLOT(_q_disconnected())); Q_ASSERT(check); check = connect(client, SIGNAL(iqReceived(QXmppIq)), this, SLOT(_q_iqReceived(QXmppIq))); Q_ASSERT(check); check = connect(client, SIGNAL(presenceReceived(QXmppPresence)), this, SLOT(_q_presenceReceived(QXmppPresence))); Q_ASSERT(check); } /// \endcond /// Initiates a new outgoing call to the specified recipient. /// /// \param jid QXmppCall *QXmppCallManager::call(const QString &jid) { bool check; Q_UNUSED(check); if (jid.isEmpty()) { warning("Refusing to call an empty jid"); return 0; } if (jid == client()->configuration().jid()) { warning("Refusing to call self"); return 0; } QXmppCall *call = new QXmppCall(jid, QXmppCall::OutgoingDirection, this); call->d->sid = QXmppUtils::generateStanzaHash(); // register call d->calls << call; check = connect(call, SIGNAL(destroyed(QObject*)), this, SLOT(_q_callDestroyed(QObject*))); Q_ASSERT(check); emit callStarted(call); call->d->sendInvite(); return call; } /// 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 QXmppCallManager::setStunServer(const QHostAddress &host, quint16 port) { d->stunHost = host; d->stunPort = 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 QXmppCallManager::setTurnServer(const QHostAddress &host, quint16 port) { d->turnHost = host; d->turnPort = port; } /// Sets the \a user used for authentication with the TURN server. /// /// \param user void QXmppCallManager::setTurnUser(const QString &user) { d->turnUser = user; } /// Sets the \a password used for authentication with the TURN server. /// /// \param password void QXmppCallManager::setTurnPassword(const QString &password) { d->turnPassword = password; } /// Handles call destruction. void QXmppCallManager::_q_callDestroyed(QObject *object) { d->calls.removeAll(static_cast(object)); } /// Handles disconnection from server. void QXmppCallManager::_q_disconnected() { foreach (QXmppCall *call, d->calls) call->d->terminate(QXmppJingleIq::Reason::Gone); } /// Handles acknowledgements. /// void QXmppCallManager::_q_iqReceived(const QXmppIq &ack) { if (ack.type() != QXmppIq::Result) return; // find request foreach (QXmppCall *call, d->calls) call->d->handleAck(ack); } /// Handles a Jingle IQ. /// void QXmppCallManager::_q_jingleIqReceived(const QXmppJingleIq &iq) { bool check; Q_UNUSED(check); if (iq.type() != QXmppIq::Set) return; if (iq.action() == QXmppJingleIq::SessionInitiate) { // build call QXmppCall *call = new QXmppCall(iq.from(), QXmppCall::IncomingDirection, this); call->d->sid = iq.sid(); const QXmppJingleIq::Content content = iq.contents().isEmpty() ? QXmppJingleIq::Content() : iq.contents().first(); QXmppCallPrivate::Stream *stream = call->d->findStreamByMedia(content.descriptionMedia()); if (!stream) return; stream->creator = content.creator(); stream->name = content.name(); // send ack call->d->sendAck(iq); // check content description and transport if (!call->d->handleDescription(stream, content) || !call->d->handleTransport(stream, content)) { // terminate call call->d->terminate(QXmppJingleIq::Reason::FailedApplication); call->terminated(); delete call; return; } // register call d->calls << call; check = connect(call, SIGNAL(destroyed(QObject*)), this, SLOT(_q_callDestroyed(QObject*))); Q_ASSERT(check); // send ringing indication QXmppJingleIq ringing; ringing.setTo(call->jid()); ringing.setType(QXmppIq::Set); ringing.setAction(QXmppJingleIq::SessionInfo); ringing.setSid(call->sid()); ringing.setRinging(true); call->d->sendRequest(ringing); // notify user emit callReceived(call); return; } else { // for all other requests, require a valid call QXmppCall *call = d->findCall(iq.sid()); if (!call) { warning(QString("Remote party %1 sent a request for an unknown call %2").arg(iq.from(), iq.sid())); return; } call->d->handleRequest(iq); } } /// Handles a presence. void QXmppCallManager::_q_presenceReceived(const QXmppPresence &presence) { if (presence.type() != QXmppPresence::Unavailable) return; foreach (QXmppCall *call, d->calls) { if (presence.from() == call->jid()) { // the remote party has gone away, terminate call call->d->terminate(QXmppJingleIq::Reason::Gone); } } } qxmpp-0.9.3/src/client/QXmppCallManager.h000066400000000000000000000143111263006255200202430ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPCALLMANAGER_H #define QXMPPCALLMANAGER_H #include #include #include #include "QXmppClientExtension.h" #include "QXmppLogger.h" class QHostAddress; class QXmppCallPrivate; class QXmppCallManager; class QXmppCallManagerPrivate; class QXmppIq; class QXmppJingleCandidate; class QXmppJingleIq; class QXmppJinglePayloadType; class QXmppPresence; class QXmppRtpAudioChannel; class QXmppRtpVideoChannel; /// \brief The QXmppCall class represents a Voice-Over-IP call to a remote party. /// /// To get the QIODevice from which you can read / write audio samples, call /// audioChannel(). /// /// \note THIS API IS NOT FINALIZED YET class QXMPP_EXPORT QXmppCall : public QXmppLoggable { Q_OBJECT Q_ENUMS(Direction State) Q_FLAGS(QIODevice::OpenModeFlag QIODevice::OpenMode) Q_PROPERTY(Direction direction READ direction CONSTANT) Q_PROPERTY(QString jid READ jid CONSTANT) Q_PROPERTY(State state READ state NOTIFY stateChanged) Q_PROPERTY(QIODevice::OpenMode audioMode READ audioMode NOTIFY audioModeChanged) Q_PROPERTY(QIODevice::OpenMode videoMode READ videoMode NOTIFY videoModeChanged) public: /// This enum is used to describe the direction of a call. enum Direction { IncomingDirection, ///< The call is incoming. OutgoingDirection ///< The call is outgoing. }; /// This enum is used to describe the state of a call. enum State { ConnectingState = 0, ///< The call is being connected. ActiveState = 1, ///< The call is active. DisconnectingState = 2, ///< The call is being disconnected. FinishedState = 3 ///< The call is finished. }; ~QXmppCall(); QXmppCall::Direction direction() const; QString jid() const; QString sid() const; QXmppCall::State state() const; QXmppRtpAudioChannel *audioChannel() const; QIODevice::OpenMode audioMode() const; QXmppRtpVideoChannel *videoChannel() const; QIODevice::OpenMode videoMode() const; signals: /// \brief This signal is emitted when a call is connected. /// /// Once this signal is emitted, you can connect a QAudioOutput and /// QAudioInput to the call. You can determine the appropriate clockrate /// and the number of channels by calling payloadType(). void connected(); /// \brief This signal is emitted when a call is finished. /// /// Note: Do not delete the call in the slot connected to this signal, /// instead use deleteLater(). void finished(); /// \brief This signal is emitted when the remote party is ringing. void ringing(); /// \brief This signal is emitted when the call state changes. void stateChanged(QXmppCall::State state); /// \brief This signal is emitted when the audio channel changes. void audioModeChanged(QIODevice::OpenMode mode); /// \brief This signal is emitted when the video channel changes. void videoModeChanged(QIODevice::OpenMode mode); public slots: void accept(); void hangup(); void startVideo(); void stopVideo(); private slots: void localCandidatesChanged(); void terminated(); void updateOpenMode(); private: QXmppCall(const QString &jid, QXmppCall::Direction direction, QXmppCallManager *parent); QXmppCallPrivate *d; friend class QXmppCallManager; friend class QXmppCallManagerPrivate; friend class QXmppCallPrivate; }; /// \brief The QXmppCallManager class provides support for making and /// receiving voice calls. /// /// Session initiation is performed as described by XEP-0166: Jingle, /// XEP-0167: Jingle RTP Sessions and XEP-0176: Jingle ICE-UDP Transport /// Method. /// /// The data stream is connected using Interactive Connectivity Establishment /// (RFC 5245) and data is transferred using Real Time Protocol (RFC 3550) /// packets. /// /// To make use of this manager, you need to instantiate it and load it into /// the QXmppClient instance as follows: /// /// \code /// QXmppCallManager *manager = new QXmppCallManager; /// client->addExtension(manager); /// \endcode /// /// \ingroup Managers class QXMPP_EXPORT QXmppCallManager : public QXmppClientExtension { Q_OBJECT public: QXmppCallManager(); ~QXmppCallManager(); 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); /// \cond QStringList discoveryFeatures() const; bool handleStanza(const QDomElement &element); /// \endcond signals: /// This signal is emitted when a new incoming call is received. /// /// To accept the call, invoke the call's QXmppCall::accept() method. /// To refuse the call, invoke the call's QXmppCall::hangup() method. void callReceived(QXmppCall *call); /// This signal is emitted when a call (incoming or outgoing) is started. void callStarted(QXmppCall *call); public slots: QXmppCall *call(const QString &jid); protected: /// \cond void setClient(QXmppClient* client); /// \endcond private slots: void _q_callDestroyed(QObject *object); void _q_disconnected(); void _q_iqReceived(const QXmppIq &iq); void _q_jingleIqReceived(const QXmppJingleIq &iq); void _q_presenceReceived(const QXmppPresence &presence); private: QXmppCallManagerPrivate *d; friend class QXmppCall; friend class QXmppCallPrivate; friend class QXmppCallManagerPrivate; }; Q_DECLARE_METATYPE(QXmppCall::State) #endif qxmpp-0.9.3/src/client/QXmppClient.cpp000066400000000000000000000402351263006255200176520ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppClient.h" #include "QXmppClientExtension.h" #include "QXmppConstants.h" #include "QXmppLogger.h" #include "QXmppOutgoingClient.h" #include "QXmppMessage.h" #include "QXmppUtils.h" #include "QXmppRosterManager.h" #include "QXmppVCardManager.h" #include "QXmppVersionManager.h" #include "QXmppEntityTimeManager.h" #include "QXmppDiscoveryManager.h" #include "QXmppDiscoveryIq.h" class QXmppClientPrivate { public: QXmppClientPrivate(QXmppClient *qq); QXmppPresence clientPresence; ///< Current presence of the client QList extensions; QXmppLogger *logger; QXmppOutgoingClient *stream; ///< Pointer to the XMPP stream // reconnection bool receivedConflict; int reconnectionTries; QTimer *reconnectionTimer; void addProperCapability(QXmppPresence& presence); int getNextReconnectTime() const; private: QXmppClient *q; }; QXmppClientPrivate::QXmppClientPrivate(QXmppClient *qq) : clientPresence(QXmppPresence::Available) , logger(0) , stream(0) , receivedConflict(false) , reconnectionTries(0) , reconnectionTimer(0) , q(qq) { } void QXmppClientPrivate::addProperCapability(QXmppPresence& presence) { QXmppDiscoveryManager* ext = q->findExtension(); if(ext) { presence.setCapabilityHash("sha-1"); presence.setCapabilityNode(ext->clientCapabilitiesNode()); presence.setCapabilityVer(ext->capabilities().verificationString()); } } int QXmppClientPrivate::getNextReconnectTime() const { if (reconnectionTries < 5) return 10 * 1000; else if (reconnectionTries < 10) return 20 * 1000; else if (reconnectionTries < 15) return 40 * 1000; else return 60 * 1000; } /// Creates a QXmppClient object. /// \param parent is passed to the QObject's constructor. /// The default value is 0. QXmppClient::QXmppClient(QObject *parent) : QXmppLoggable(parent), d(new QXmppClientPrivate(this)) { bool check; Q_UNUSED(check); d->stream = new QXmppOutgoingClient(this); d->addProperCapability(d->clientPresence); check = connect(d->stream, SIGNAL(elementReceived(QDomElement,bool&)), this, SLOT(_q_elementReceived(QDomElement,bool&))); Q_ASSERT(check); check = connect(d->stream, SIGNAL(messageReceived(QXmppMessage)), this, SIGNAL(messageReceived(QXmppMessage))); Q_ASSERT(check); check = connect(d->stream, SIGNAL(presenceReceived(QXmppPresence)), this, SIGNAL(presenceReceived(QXmppPresence))); Q_ASSERT(check); check = connect(d->stream, SIGNAL(iqReceived(QXmppIq)), this, SIGNAL(iqReceived(QXmppIq))); Q_ASSERT(check); check = connect(d->stream, SIGNAL(sslErrors(QList)), this, SIGNAL(sslErrors(QList))); Q_ASSERT(check); check = connect(d->stream->socket(), SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(_q_socketStateChanged(QAbstractSocket::SocketState))); Q_ASSERT(check); check = connect(d->stream, SIGNAL(connected()), this, SLOT(_q_streamConnected())); Q_ASSERT(check); check = connect(d->stream, SIGNAL(disconnected()), this, SLOT(_q_streamDisconnected())); Q_ASSERT(check); check = connect(d->stream, SIGNAL(error(QXmppClient::Error)), this, SLOT(_q_streamError(QXmppClient::Error))); Q_ASSERT(check); // reconnection d->reconnectionTimer = new QTimer(this); d->reconnectionTimer->setSingleShot(true); connect(d->reconnectionTimer, SIGNAL(timeout()), this, SLOT(_q_reconnect())); Q_ASSERT(check); // logging setLogger(QXmppLogger::getLogger()); addExtension(new QXmppRosterManager(this)); addExtension(new QXmppVCardManager); addExtension(new QXmppVersionManager); addExtension(new QXmppEntityTimeManager()); addExtension(new QXmppDiscoveryManager()); } /// Destructor, destroys the QXmppClient object. /// QXmppClient::~QXmppClient() { delete d; } /// Registers a new \a extension with the client. /// /// \param extension bool QXmppClient::addExtension(QXmppClientExtension* extension) { return insertExtension(d->extensions.size(), extension); } /// Registers a new \a extension with the client at the given \a index. /// /// \param index /// \param extension bool QXmppClient::insertExtension(int index, QXmppClientExtension *extension) { if (d->extensions.contains(extension)) { qWarning("Cannot add extension, it has already been added"); return false; } extension->setParent(this); extension->setClient(this); d->extensions.insert(index, extension); return true; } /// Unregisters the given extension from the client. If the extension /// is found, it will be destroyed. /// /// \param extension bool QXmppClient::removeExtension(QXmppClientExtension* extension) { if (d->extensions.contains(extension)) { d->extensions.removeAll(extension); delete extension; return true; } else { qWarning("Cannot remove extension, it was never added"); return false; } } /// Returns a list containing all the client's extensions. /// QList QXmppClient::extensions() { return d->extensions; } /// Returns a modifiable reference to the current configuration of QXmppClient. /// \return Reference to the QXmppClient's configuration for the connection. QXmppConfiguration& QXmppClient::configuration() { return d->stream->configuration(); } /// Attempts to connect to the XMPP server. Server details and other configurations /// are specified using the config parameter. Use signals connected(), error(QXmppClient::Error) /// and disconnected() to know the status of the connection. /// \param config Specifies the configuration object for connecting the XMPP server. /// This contains the host name, user, password etc. See QXmppConfiguration for details. /// \param initialPresence The initial presence which will be set for this user /// after establishing the session. The default value is QXmppPresence::Available void QXmppClient::connectToServer(const QXmppConfiguration& config, const QXmppPresence& initialPresence) { d->stream->configuration() = config; d->clientPresence = initialPresence; d->addProperCapability(d->clientPresence); d->stream->connectToHost(); } /// Overloaded function to simply connect to an XMPP server with a JID and password. /// /// \param jid JID for the account. /// \param password Password for the account. void QXmppClient::connectToServer(const QString &jid, const QString &password) { QXmppConfiguration config; config.setJid(jid); config.setPassword(password); connectToServer(config); } /// After successfully connecting to the server use this function to send /// stanzas to the server. This function can solely be used to send various kind /// of stanzas to the server. QXmppStanza is a parent class of all the stanzas /// QXmppMessage, QXmppPresence, QXmppIq, QXmppBind, QXmppRosterIq, QXmppSession /// and QXmppVCard. /// /// \return Returns true if the packet was sent, false otherwise. /// /// Following code snippet illustrates how to send a message using this function: /// \code /// QXmppMessage message(from, to, message); /// client.sendPacket(message); /// \endcode /// /// \param packet A valid XMPP stanza. It can be an iq, a message or a presence stanza. /// bool QXmppClient::sendPacket(const QXmppStanza& packet) { return d->stream->sendPacket(packet); } /// Disconnects the client and the current presence of client changes to /// QXmppPresence::Unavailable and status text changes to "Logged out". /// /// \note Make sure that the clientPresence is changed to /// QXmppPresence::Available, if you are again calling connectToServer() after /// calling the disconnectFromServer() function. /// void QXmppClient::disconnectFromServer() { // cancel reconnection d->reconnectionTimer->stop(); d->clientPresence.setType(QXmppPresence::Unavailable); d->clientPresence.setStatusText("Logged out"); if (d->stream->isConnected()) sendPacket(d->clientPresence); d->stream->disconnectFromHost(); } /// Returns true if the client has authenticated with the XMPP server. bool QXmppClient::isAuthenticated() const { return d->stream->isAuthenticated(); } /// Returns true if the client is connected to the XMPP server. /// bool QXmppClient::isConnected() const { return d->stream->isConnected(); } /// Returns the reference to QXmppRosterManager object of the client. /// \return Reference to the roster object of the connected client. Use this to /// get the list of friends in the roster and their presence information. /// QXmppRosterManager& QXmppClient::rosterManager() { return *findExtension(); } /// Utility function to send message to all the resources associated with the /// specified bareJid. If there are no resources available, that is the contact /// is offline or not present in the roster, it will still send a message to /// the bareJid. /// /// \param bareJid bareJid of the receiving entity /// \param message Message string to be sent. void QXmppClient::sendMessage(const QString& bareJid, const QString& message) { QStringList resources = rosterManager().getResources(bareJid); if(!resources.isEmpty()) { for(int i = 0; i < resources.size(); ++i) { sendPacket(QXmppMessage("", bareJid + "/" + resources.at(i), message)); } } else { sendPacket(QXmppMessage("", bareJid, message)); } } /// Returns the client's current state. QXmppClient::State QXmppClient::state() const { if (d->stream->isConnected()) return QXmppClient::ConnectedState; else if (d->stream->socket()->state() != QAbstractSocket::UnconnectedState && d->stream->socket()->state() != QAbstractSocket::ClosingState) return QXmppClient::ConnectingState; else return QXmppClient::DisconnectedState; } /// Returns the client's current presence. /// QXmppPresence QXmppClient::clientPresence() const { return d->clientPresence; } /// Changes the presence of the connected client. /// /// The connection to the server will be updated accordingly: /// /// \li If the presence type is QXmppPresence::Unavailable, the connection /// to the server will be closed. /// /// \li Otherwise, the connection to the server will be established /// as needed. /// /// \param presence QXmppPresence object /// void QXmppClient::setClientPresence(const QXmppPresence& presence) { d->clientPresence = presence; d->addProperCapability(d->clientPresence); if (presence.type() == QXmppPresence::Unavailable) { // cancel reconnection d->reconnectionTimer->stop(); // NOTE: we can't call disconnect() because it alters // the client presence if (d->stream->isConnected()) sendPacket(d->clientPresence); d->stream->disconnectFromHost(); } else if (d->stream->isConnected()) sendPacket(d->clientPresence); else connectToServer(d->stream->configuration(), presence); } /// Returns the socket error if error() is QXmppClient::SocketError. /// QAbstractSocket::SocketError QXmppClient::socketError() { return d->stream->socket()->error(); } /// Returns the human-readable description of the last socket error if error() is QXmppClient::SocketError. /// QString QXmppClient::socketErrorString() const { return d->stream->socket()->errorString(); } /// Returns the XMPP stream error if QXmppClient::Error is QXmppClient::XmppStreamError. /// QXmppStanza::Error::Condition QXmppClient::xmppStreamError() { return d->stream->xmppStreamError(); } /// Returns the reference to QXmppVCardManager, implementation of XEP-0054. /// http://xmpp.org/extensions/xep-0054.html /// QXmppVCardManager& QXmppClient::vCardManager() { return *findExtension(); } /// Returns the reference to QXmppVersionManager, implementation of XEP-0092. /// http://xmpp.org/extensions/xep-0092.html /// QXmppVersionManager& QXmppClient::versionManager() { return *findExtension(); } /// Give extensions a chance to handle incoming stanzas. /// /// \param element /// \param handled void QXmppClient::_q_elementReceived(const QDomElement &element, bool &handled) { foreach (QXmppClientExtension *extension, d->extensions) { if (extension->handleStanza(element)) { handled = true; return; } } } void QXmppClient::_q_reconnect() { if (d->stream->configuration().autoReconnectionEnabled()) { debug("Reconnecting to server"); d->stream->connectToHost(); } } void QXmppClient::_q_socketStateChanged(QAbstractSocket::SocketState socketState) { Q_UNUSED(socketState); emit stateChanged(state()); } /// At connection establishment, send initial presence. void QXmppClient::_q_streamConnected() { d->receivedConflict = false; d->reconnectionTries = 0; // notify managers emit connected(); emit stateChanged(QXmppClient::ConnectedState); // send initial presence if (d->stream->isAuthenticated()) sendPacket(d->clientPresence); } void QXmppClient::_q_streamDisconnected() { // notify managers emit disconnected(); emit stateChanged(QXmppClient::DisconnectedState); } void QXmppClient::_q_streamError(QXmppClient::Error err) { if (d->stream->configuration().autoReconnectionEnabled()) { if (err == QXmppClient::XmppStreamError) { // if we receive a resource conflict, inhibit reconnection if (d->stream->xmppStreamError() == QXmppStanza::Error::Conflict) d->receivedConflict = true; } else if (err == QXmppClient::SocketError && !d->receivedConflict) { // schedule reconnect d->reconnectionTimer->start(d->getNextReconnectTime()); } else if (err == QXmppClient::KeepAliveError) { // if we got a keepalive error, reconnect in one second d->reconnectionTimer->start(1000); } } // notify managers emit error(err); } /// Returns the QXmppLogger associated with the current QXmppClient. QXmppLogger *QXmppClient::logger() const { return d->logger; } /// Sets the QXmppLogger associated with the current QXmppClient. void QXmppClient::setLogger(QXmppLogger *logger) { if (logger != d->logger) { if (d->logger) { disconnect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), d->logger, SLOT(log(QXmppLogger::MessageType,QString))); disconnect(this, SIGNAL(setGauge(QString,double)), d->logger, SLOT(setGauge(QString,double))); disconnect(this, SIGNAL(updateCounter(QString,qint64)), d->logger, SLOT(updateCounter(QString,qint64))); } d->logger = logger; if (d->logger) { connect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), d->logger, SLOT(log(QXmppLogger::MessageType,QString))); connect(this, SIGNAL(setGauge(QString,double)), d->logger, SLOT(setGauge(QString,double))); connect(this, SIGNAL(updateCounter(QString,qint64)), d->logger, SLOT(updateCounter(QString,qint64))); } emit loggerChanged(d->logger); } } qxmpp-0.9.3/src/client/QXmppClient.h000066400000000000000000000201371263006255200173160ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 QXMPPCLIENT_H #define QXMPPCLIENT_H #include #include #include "QXmppConfiguration.h" #include "QXmppLogger.h" #include "QXmppPresence.h" class QSslError; class QXmppClientExtension; class QXmppClientPrivate; class QXmppPresence; class QXmppMessage; class QXmppIq; class QXmppStream; // managers class QXmppDiscoveryIq; class QXmppRosterManager; class QXmppVCardManager; class QXmppVersionManager; /// \defgroup Core /// \defgroup Managers /// \brief The QXmppClient class is the main class for using QXmpp. /// /// It provides the user all the required functionality to connect to the /// server and perform operations afterwards. /// /// This class will provide the handle/reference to QXmppRosterManager /// (roster management), QXmppVCardManager (vCard manager), and /// QXmppVersionManager (software version information). /// /// By default, the client will automatically try reconnecting to the server. /// You can change this a behaviour using /// QXmppConfiguration::setAutoReconnectionEnabled(). /// /// Not all the managers or extensions have been enabled by default. One can /// enable/disable the managers using the funtions addExtension() and /// removeExtension(). findExtension() can be used to find reference/pointer to /// particular instansiated and enabled manager. /// /// List of managers enabled by default: /// - QXmppRosterManager /// - QXmppVCardManager /// - QXmppVersionManager /// - QXmppDiscoveryManager /// - QXmppEntityTimeManager /// /// \ingroup Core class QXMPP_EXPORT QXmppClient : public QXmppLoggable { Q_OBJECT Q_ENUMS(Error State) Q_PROPERTY(QXmppLogger* logger READ logger WRITE setLogger NOTIFY loggerChanged) Q_PROPERTY(State state READ state NOTIFY stateChanged) public: /// An enumeration for type of error. /// Error could come due a TCP socket or XML stream or due to various stanzas. enum Error { NoError, ///< No error. SocketError, ///< Error due to TCP socket. KeepAliveError, ///< Error due to no response to a keep alive. XmppStreamError ///< Error due to XML stream. }; /// This enumeration describes a client state. enum State { DisconnectedState, ///< Disconnected from the server. ConnectingState, ///< Trying to connect to the server. ConnectedState ///< Connected to the server. }; QXmppClient(QObject *parent = 0); ~QXmppClient(); bool addExtension(QXmppClientExtension* extension); bool insertExtension(int index, QXmppClientExtension* extension); bool removeExtension(QXmppClientExtension* extension); QList extensions(); /// \brief Returns the extension which can be cast into type T*, or 0 /// if there is no such extension. /// /// Usage example: /// \code /// QXmppDiscoveryManager* ext = client->findExtension(); /// if(ext) /// { /// //extension found, do stuff... /// } /// \endcode /// template T* findExtension() { QList list = extensions(); for (int i = 0; i < list.size(); ++i) { T* extension = qobject_cast(list.at(i)); if(extension) return extension; } return 0; } bool isAuthenticated() const; bool isConnected() const; QXmppPresence clientPresence() const; void setClientPresence(const QXmppPresence &presence); QXmppConfiguration &configuration(); QXmppLogger *logger() const; void setLogger(QXmppLogger *logger); QAbstractSocket::SocketError socketError(); QString socketErrorString() const; State state() const; QXmppStanza::Error::Condition xmppStreamError(); QXmppRosterManager& rosterManager(); QXmppVCardManager& vCardManager(); QXmppVersionManager& versionManager(); signals: /// This signal is emitted when the client connects successfully to the XMPP /// server i.e. when a successful XMPP connection is established. /// XMPP Connection involves following sequential steps: /// - TCP socket connection /// - Client sends start stream /// - Server sends start stream /// - TLS negotiation (encryption) /// - Authentication /// - Resource binding /// - Session establishment /// /// After all these steps a successful XMPP connection is established and /// connected() signal is emitted. /// /// After the connected() signal is emitted QXmpp will send the roster request /// to the server. On receiving the roster, QXmpp will emit /// QXmppRosterManager::rosterReceived(). After this signal, QXmppRosterManager object gets /// populated and you can use rosterManager() to get the handle of QXmppRosterManager object. /// void connected(); /// This signal is emitted when the XMPP connection disconnects. /// void disconnected(); /// This signal is emitted when the XMPP connection encounters any error. /// The QXmppClient::Error parameter specifies the type of error occurred. /// It could be due to TCP socket or the xml stream or the stanza. /// Depending upon the type of error occurred use the respective get function to /// know the error. void error(QXmppClient::Error); /// This signal is emitted when the logger changes. void loggerChanged(QXmppLogger *logger); /// Notifies that an XMPP message stanza is received. The QXmppMessage /// parameter contains the details of the message sent to this client. /// In other words whenever someone sends you a message this signal is /// emitted. void messageReceived(const QXmppMessage &message); /// Notifies that an XMPP presence stanza is received. The QXmppPresence /// parameter contains the details of the presence sent to this client. /// This signal is emitted when someone login/logout or when someone's status /// changes Busy, Idle, Invisible etc. void presenceReceived(const QXmppPresence &presence); /// Notifies that an XMPP iq stanza is received. The QXmppIq /// parameter contains the details of the iq sent to this client. /// IQ stanzas provide a structured request-response mechanism. Roster /// management, setting-getting vCards etc is done using iq stanzas. void iqReceived(const QXmppIq &iq); /// This signal is emitted to indicate that one or more SSL errors were /// encountered while establishing the identity of the server. void sslErrors(const QList &errors); /// This signal is emitted when the client state changes. void stateChanged(QXmppClient::State state); public slots: void connectToServer(const QXmppConfiguration&, const QXmppPresence& initialPresence = QXmppPresence()); void connectToServer(const QString &jid, const QString &password); void disconnectFromServer(); bool sendPacket(const QXmppStanza&); void sendMessage(const QString& bareJid, const QString& message); private slots: void _q_elementReceived(const QDomElement &element, bool &handled); void _q_reconnect(); void _q_socketStateChanged(QAbstractSocket::SocketState state); void _q_streamConnected(); void _q_streamDisconnected(); void _q_streamError(QXmppClient::Error error); private: QXmppClientPrivate * const d; }; #endif // QXMPPCLIENT_H qxmpp-0.9.3/src/client/QXmppClientExtension.cpp000066400000000000000000000033241263006255200215450ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppClientExtension.h" class QXmppClientExtensionPrivate { public: QXmppClient *client; }; /// Constructs a QXmppClient extension. /// QXmppClientExtension::QXmppClientExtension() : d(new QXmppClientExtensionPrivate) { d->client = 0; } /// Destroys a QXmppClient extension. /// QXmppClientExtension::~QXmppClientExtension() { delete d; } /// Returns the discovery features to add to the client. /// QStringList QXmppClientExtension::discoveryFeatures() const { return QStringList(); } /// Returns the discovery identities to add to the client. /// QList QXmppClientExtension::discoveryIdentities() const { return QList(); } /// Returns the client which loaded this extension. /// QXmppClient *QXmppClientExtension::client() { return d->client; } /// Sets the client which loaded this extension. /// /// \param client void QXmppClientExtension::setClient(QXmppClient *client) { d->client = client; } qxmpp-0.9.3/src/client/QXmppClientExtension.h000066400000000000000000000041221263006255200212070ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPCLIENTEXTENSION_H #define QXMPPCLIENTEXTENSION_H #include "QXmppDiscoveryIq.h" #include "QXmppLogger.h" class QDomElement; class QStringList; class QXmppClient; class QXmppClientExtensionPrivate; class QXmppStream; /// \brief The QXmppClientExtension class is the base class for QXmppClient /// extensions. /// /// If you want to extend QXmppClient, for instance to support an IQ type /// which is not natively supported, you can subclass QXmppClientExtension /// and implement handleStanza(). You can then add your extension to the /// client instance using QXmppClient::addExtension(). /// /// \ingroup Core class QXMPP_EXPORT QXmppClientExtension : public QXmppLoggable { Q_OBJECT public: QXmppClientExtension(); virtual ~QXmppClientExtension(); virtual QStringList discoveryFeatures() const; virtual QList discoveryIdentities() const; /// \brief You need to implement this method to process incoming XMPP /// stanzas. /// /// You should return true if the stanza was handled and no further /// processing should occur, or false to let other extensions process /// the stanza. virtual bool handleStanza(const QDomElement &stanza) = 0; protected: QXmppClient *client(); virtual void setClient(QXmppClient *client); private: QXmppClientExtensionPrivate * const d; friend class QXmppClient; }; #endif qxmpp-0.9.3/src/client/QXmppConfiguration.cpp000066400000000000000000000342521263006255200212450ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppConfiguration.h" #include "QXmppUtils.h" class QXmppConfigurationPrivate : public QSharedData { public: QXmppConfigurationPrivate(); QString host; int port; QString user; QString password; QString domain; QString resource; // Facebook QString facebookAccessToken; QString facebookAppId; // Google QString googleAccessToken; // Windows Live QString windowsLiveAccessToken; // default is false bool autoAcceptSubscriptions; // default is true bool sendIntialPresence; // default is true bool sendRosterRequest; // interval in seconds, if zero won't ping int keepAliveInterval; // interval in seconds, if zero won't timeout int keepAliveTimeout; // will keep reconnecting if disconnected, default is true bool autoReconnectionEnabled; // which authentication systems to use (if any) bool useSASLAuthentication; bool useNonSASLAuthentication; // default is true bool ignoreSslErrors; QXmppConfiguration::StreamSecurityMode streamSecurityMode; QXmppConfiguration::NonSASLAuthMechanism nonSASLAuthMechanism; QString saslAuthMechanism; QNetworkProxy networkProxy; QList caCertificates; }; QXmppConfigurationPrivate::QXmppConfigurationPrivate() : port(5222) , resource("QXmpp") , autoAcceptSubscriptions(false) , sendIntialPresence(true) , sendRosterRequest(true) , keepAliveInterval(60) , keepAliveTimeout(20) , autoReconnectionEnabled(true) , useSASLAuthentication(true) , useNonSASLAuthentication(true) , ignoreSslErrors(true) , streamSecurityMode(QXmppConfiguration::TLSEnabled) , nonSASLAuthMechanism(QXmppConfiguration::NonSASLDigest) , saslAuthMechanism("DIGEST-MD5") { } /// Creates a QXmppConfiguration object. QXmppConfiguration::QXmppConfiguration() : d(new QXmppConfigurationPrivate) { } /// Creates a copy of \a other. QXmppConfiguration::QXmppConfiguration(const QXmppConfiguration &other) : d(other.d) { } /// Destructor, destroys the QXmppConfiguration object. /// QXmppConfiguration::~QXmppConfiguration() { } /// Assigns \a other to this QXmppConfiguration. QXmppConfiguration& QXmppConfiguration::operator=(const QXmppConfiguration &other) { d = other.d; return *this; } /// Sets the host name. /// /// \param host host name of the XMPP server where connection has to be made /// (e.g. "jabber.org" and "talk.google.com"). It can also be an IP address in /// the form of a string (e.g. "192.168.1.25"). /// void QXmppConfiguration::setHost(const QString& host) { d->host = host; } /// Sets the domain name. /// /// \param domain Domain name e.g. "gmail.com" and "jabber.org". /// \note host name and domain name can be different for google /// domain name is gmail.com and host name is talk.google.com /// void QXmppConfiguration::setDomain(const QString& domain) { d->domain = domain; } /// Sets the port number. /// /// \param port Port number at which the XMPP server is listening. The default /// value is 5222. /// void QXmppConfiguration::setPort(int port) { d->port = port; } /// Sets the username. /// /// \param user Username of the account at the specified XMPP server. It should /// be the name without the domain name. E.g. "qxmpp.test1" and not /// "qxmpp.test1@gmail.com" /// void QXmppConfiguration::setUser(const QString& user) { d->user = user; } /// Sets the password. /// /// \param password Password for the specified username /// void QXmppConfiguration::setPassword(const QString& password) { d->password = password; } /// Sets the resource identifier. /// /// Multiple resources (e.g., devices or locations) may connect simultaneously /// to a server on behalf of each authorized client, with each resource /// differentiated by the resource identifier of an XMPP address /// (e.g. node\@domain/home vs. node\@domain/work) /// /// The default value is "QXmpp". /// /// \param resource Resource identifier of the client in connection. void QXmppConfiguration::setResource(const QString& resource) { d->resource = resource; } /// Sets the JID. If a full JID (i.e. one with a resource) is given, calling /// this method will update the username, domain and resource. Otherwise, only /// the username and the domain will be updated. /// /// \param jid void QXmppConfiguration::setJid(const QString& jid) { d->user = QXmppUtils::jidToUser(jid); d->domain = QXmppUtils::jidToDomain(jid); const QString resource = QXmppUtils::jidToResource(jid); if (!resource.isEmpty()) d->resource = resource; } /// Returns the host name. /// /// \return host name /// QString QXmppConfiguration::host() const { return d->host; } /// Returns the domain name. /// /// \return domain name /// QString QXmppConfiguration::domain() const { return d->domain; } /// Returns the port number. /// /// \return port number /// int QXmppConfiguration::port() const { return d->port; } /// Returns the username. /// /// \return username /// QString QXmppConfiguration::user() const { return d->user; } /// Returns the password. /// /// \return password /// QString QXmppConfiguration::password() const { return d->password; } /// Returns the resource identifier. /// /// \return resource identifier /// QString QXmppConfiguration::resource() const { return d->resource; } /// Returns the jabber id (jid). /// /// \return jabber id (jid) /// (e.g. "qxmpp.test1@gmail.com/resource" or qxmpptest@jabber.org/QXmpp156) /// QString QXmppConfiguration::jid() const { if (d->user.isEmpty()) return d->domain; else return jidBare() + "/" + d->resource; } /// Returns the bare jabber id (jid), without the resource identifier. /// /// \return bare jabber id (jid) /// (e.g. "qxmpp.test1@gmail.com" or qxmpptest@jabber.org) /// QString QXmppConfiguration::jidBare() const { if (d->user.isEmpty()) return d->domain; else return d->user+"@"+d->domain; } /// Returns the access token used for X-FACEBOOK-PLATFORM authentication. QString QXmppConfiguration::facebookAccessToken() const { return d->facebookAccessToken; } /// Sets the access token used for X-FACEBOOK-PLATFORM authentication. /// /// This token is returned by Facebook at the end of the OAuth authentication /// process. /// /// \param accessToken void QXmppConfiguration::setFacebookAccessToken(const QString& accessToken) { d->facebookAccessToken = accessToken; } /// Returns the application ID used for X-FACEBOOK-PLATFORM authentication. QString QXmppConfiguration::facebookAppId() const { return d->facebookAppId; } /// Sets the application ID used for X-FACEBOOK-PLATFORM authentication. /// /// \param appId void QXmppConfiguration::setFacebookAppId(const QString& appId) { d->facebookAppId = appId; } /// Returns the access token used for X-OAUTH2 authentication. QString QXmppConfiguration::googleAccessToken() const { return d->googleAccessToken; } /// Sets the access token used for X-OAUTH2 authentication. /// /// This token is returned by Google at the end of the OAuth authentication /// process. /// /// \param accessToken void QXmppConfiguration::setGoogleAccessToken(const QString& accessToken) { d->googleAccessToken = accessToken; } /// Returns the access token used for X-MESSENGER-OAUTH2 authentication. QString QXmppConfiguration::windowsLiveAccessToken() const { return d->windowsLiveAccessToken; } /// Sets the access token used for X-MESSENGER-OAUTH2 authentication. /// /// This token is returned by Windows Live at the end of the OAuth authentication /// process. /// /// \param accessToken void QXmppConfiguration::setWindowsLiveAccessToken(const QString& accessToken) { d->windowsLiveAccessToken = accessToken; } /// Returns the auto-accept-subscriptions-request configuration. /// /// \return boolean value /// true means that auto-accept-subscriptions-request is enabled else disabled for false /// bool QXmppConfiguration::autoAcceptSubscriptions() const { return d->autoAcceptSubscriptions; } /// Sets the auto-accept-subscriptions-request configuration. /// /// \param value boolean value /// true means that auto-accept-subscriptions-request is enabled else disabled for false /// void QXmppConfiguration::setAutoAcceptSubscriptions(bool value) { d->autoAcceptSubscriptions = value; } /// Returns the auto-reconnect-on-disconnection-on-error configuration. /// /// \return boolean value /// true means that auto-reconnect is enabled else disabled for false /// bool QXmppConfiguration::autoReconnectionEnabled() const { return d->autoReconnectionEnabled; } /// Sets the auto-reconnect-on-disconnection-on-error configuration. /// /// \param value boolean value /// true means that auto-reconnect is enabled else disabled for false /// void QXmppConfiguration::setAutoReconnectionEnabled(bool value) { d->autoReconnectionEnabled = value; } /// Returns whether SSL errors (such as certificate validation errors) /// are to be ignored when connecting to the XMPP server. bool QXmppConfiguration::ignoreSslErrors() const { return d->ignoreSslErrors; } /// Specifies whether SSL errors (such as certificate validation errors) /// are to be ignored when connecting to an XMPP server. void QXmppConfiguration::setIgnoreSslErrors(bool value) { d->ignoreSslErrors = value; } /// Returns whether to make use of SASL authentication. bool QXmppConfiguration::useSASLAuthentication() const { return d->useSASLAuthentication; } /// Sets whether to make use of SASL authentication. void QXmppConfiguration::setUseSASLAuthentication(bool useSASL) { d->useSASLAuthentication = useSASL; } /// Returns whether to make use of non-SASL authentication. bool QXmppConfiguration::useNonSASLAuthentication() const { return d->useNonSASLAuthentication; } /// Sets whether to make use of non-SASL authentication. void QXmppConfiguration::setUseNonSASLAuthentication(bool useNonSASL) { d->useNonSASLAuthentication = useNonSASL; } /// Returns the specified security mode for the stream. The default value is /// QXmppConfiguration::TLSEnabled. /// \return StreamSecurityMode QXmppConfiguration::StreamSecurityMode QXmppConfiguration::streamSecurityMode() const { return d->streamSecurityMode; } /// Specifies the specified security mode for the stream. The default value is /// QXmppConfiguration::TLSEnabled. /// \param mode StreamSecurityMode void QXmppConfiguration::setStreamSecurityMode( QXmppConfiguration::StreamSecurityMode mode) { d->streamSecurityMode = mode; } /// Returns the Non-SASL authentication mechanism configuration. /// /// \return QXmppConfiguration::NonSASLAuthMechanism /// QXmppConfiguration::NonSASLAuthMechanism QXmppConfiguration::nonSASLAuthMechanism() const { return d->nonSASLAuthMechanism; } /// Hints the library the Non-SASL authentication mechanism to be used for authentication. /// /// \param mech QXmppConfiguration::NonSASLAuthMechanism /// void QXmppConfiguration::setNonSASLAuthMechanism( QXmppConfiguration::NonSASLAuthMechanism mech) { d->nonSASLAuthMechanism = mech; } /// Returns the preferred SASL authentication mechanism. /// /// Default value: "DIGEST-MD5" QString QXmppConfiguration::saslAuthMechanism() const { return d->saslAuthMechanism; } /// Sets the preferred SASL authentication \a mechanism. /// /// Valid values: "PLAIN", "DIGEST-MD5", "ANONYMOUS", "X-FACEBOOK-PLATFORM" void QXmppConfiguration::setSaslAuthMechanism(const QString &mechanism) { d->saslAuthMechanism = mechanism; } /// Specifies the network proxy used for the connection made by QXmppClient. /// The default value is QNetworkProxy::DefaultProxy that is the proxy is /// determined based on the application proxy set using /// QNetworkProxy::setApplicationProxy(). /// \param proxy QNetworkProxy void QXmppConfiguration::setNetworkProxy(const QNetworkProxy& proxy) { d->networkProxy = proxy; } /// Returns the specified network proxy. /// The default value is QNetworkProxy::DefaultProxy that is the proxy is /// determined based on the application proxy set using /// QNetworkProxy::setApplicationProxy(). /// \return QNetworkProxy QNetworkProxy QXmppConfiguration::networkProxy() const { return d->networkProxy; } /// Specifies the interval in seconds at which keep alive (ping) packets /// will be sent to the server. /// /// If set to zero, no keep alive packets will be sent. /// /// The default value is 60 seconds. void QXmppConfiguration::setKeepAliveInterval(int secs) { d->keepAliveInterval = secs; } /// Returns the keep alive interval in seconds. /// /// The default value is 60 seconds. int QXmppConfiguration::keepAliveInterval() const { return d->keepAliveInterval; } /// Specifies the maximum time in seconds to wait for a keep alive response /// from the server before considering we are disconnected. /// /// If set to zero or a value larger than the keep alive interval, /// no timeout will occur. /// /// The default value is 20 seconds. void QXmppConfiguration::setKeepAliveTimeout(int secs) { d->keepAliveTimeout = secs; } /// Returns the keep alive timeout in seconds. /// /// The default value is 20 seconds. int QXmppConfiguration::keepAliveTimeout() const { return d->keepAliveTimeout; } /// Specifies a list of trusted CA certificates. void QXmppConfiguration::setCaCertificates(const QList &caCertificates) { d->caCertificates = caCertificates; } /// Returns the a list of trusted CA certificates. QList QXmppConfiguration::caCertificates() const { return d->caCertificates; } qxmpp-0.9.3/src/client/QXmppConfiguration.h000066400000000000000000000114541263006255200207110ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 QXMPPCONFIGURATION_H #define QXMPPCONFIGURATION_H #include #include #include "QXmppGlobal.h" class QNetworkProxy; class QSslCertificate; class QXmppConfigurationPrivate; /// \brief The QXmppConfiguration class holds configuration options. /// /// It can be passed to QXmppClient to specify the options when connecting to /// an XMPP server. /// /// It is a container of all the settings, configuration required for /// connecting to an XMPP server. E.g. server name, username, port, type /// of authentication mechanism, type of security used by stream (encryption), /// etc.. /// class QXMPP_EXPORT QXmppConfiguration { public: /// An enumeration for type of the Security Mode that is stream is encrypted or not. /// The server may or may not have TLS feature. Server may force the encryption. /// Depending upon all this user can specify following options. enum StreamSecurityMode { TLSEnabled = 0, ///< Encryption is used if available (default). TLSDisabled, ///< No encryption even if the server offers it. TLSRequired, ///< Encryption must be available, otherwise the ///< connection will not be established. LegacySSL ///< Use only legacy SSL mode. }; /// An enumeration for various Non-SASL authentication mechanisms available. /// The server may or may not allow QXmppConfiguration::Plain mechanism. So /// specifying the mechanism is just a hint to the library. enum NonSASLAuthMechanism { NonSASLPlain = 0,///< Plain NonSASLDigest ///< Digest (default) }; /// An enumeration for various SASL authentication mechanisms available. /// The server may or may not allow any particular mechanism. So depending /// upon the availability of mechanisms on the server the library will choose /// a mechanism. QXmppConfiguration(); QXmppConfiguration(const QXmppConfiguration &other); ~QXmppConfiguration(); QXmppConfiguration& operator=(const QXmppConfiguration &other); QString host() const; void setHost(const QString&); QString domain() const; void setDomain(const QString&); int port() const; void setPort(int); QString user() const; void setUser(const QString&); QString password() const; void setPassword(const QString&); QString resource() const; void setResource(const QString&); QString jid() const; void setJid(const QString &jid); QString jidBare() const; QString facebookAccessToken() const; void setFacebookAccessToken(const QString&); QString facebookAppId() const; void setFacebookAppId(const QString&); QString googleAccessToken() const; void setGoogleAccessToken(const QString &accessToken); QString windowsLiveAccessToken() const; void setWindowsLiveAccessToken(const QString &accessToken); bool autoAcceptSubscriptions() const; void setAutoAcceptSubscriptions(bool); bool autoReconnectionEnabled() const; void setAutoReconnectionEnabled(bool); bool useSASLAuthentication() const; void setUseSASLAuthentication(bool); bool useNonSASLAuthentication() const; void setUseNonSASLAuthentication(bool); bool ignoreSslErrors() const; void setIgnoreSslErrors(bool); QXmppConfiguration::StreamSecurityMode streamSecurityMode() const; void setStreamSecurityMode(QXmppConfiguration::StreamSecurityMode mode); QXmppConfiguration::NonSASLAuthMechanism nonSASLAuthMechanism() const; void setNonSASLAuthMechanism(QXmppConfiguration::NonSASLAuthMechanism); QString saslAuthMechanism() const; void setSaslAuthMechanism(const QString &mechanism); QNetworkProxy networkProxy() const; void setNetworkProxy(const QNetworkProxy& proxy); int keepAliveInterval() const; void setKeepAliveInterval(int secs); int keepAliveTimeout() const; void setKeepAliveTimeout(int secs); QList caCertificates() const; void setCaCertificates(const QList &); private: QSharedDataPointer d; }; #endif // QXMPPCONFIGURATION_H qxmpp-0.9.3/src/client/QXmppDiscoveryManager.cpp000066400000000000000000000175771263006255200217130ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppDiscoveryManager.h" #include #include #include "QXmppClient.h" #include "QXmppConstants.h" #include "QXmppDataForm.h" #include "QXmppDiscoveryIq.h" #include "QXmppStream.h" #include "QXmppGlobal.h" class QXmppDiscoveryManagerPrivate { public: QString clientCapabilitiesNode; QString clientCategory; QString clientType; QString clientName; QXmppDataForm clientInfoForm; }; QXmppDiscoveryManager::QXmppDiscoveryManager() : d(new QXmppDiscoveryManagerPrivate) { d->clientCapabilitiesNode = "https://github.com/qxmpp-project/qxmpp"; d->clientCategory = "client"; d->clientType = "pc"; if (qApp->applicationName().isEmpty() && qApp->applicationVersion().isEmpty()) d->clientName = QString("%1 %2").arg("Based on QXmpp", QXmppVersion()); else d->clientName = QString("%1 %2").arg(qApp->applicationName(), qApp->applicationVersion()); } QXmppDiscoveryManager::~QXmppDiscoveryManager() { delete d; } /// Requests information from the specified XMPP entity. /// /// \param jid The target entity's JID. /// \param node The target node (optional). QString QXmppDiscoveryManager::requestInfo(const QString& jid, const QString& node) { QXmppDiscoveryIq request; request.setType(QXmppIq::Get); request.setQueryType(QXmppDiscoveryIq::InfoQuery); request.setTo(jid); if(!node.isEmpty()) request.setQueryNode(node); if(client()->sendPacket(request)) return request.id(); else return QString(); } /// Requests items from the specified XMPP entity. /// /// \param jid The target entity's JID. /// \param node The target node (optional). QString QXmppDiscoveryManager::requestItems(const QString& jid, const QString& node) { QXmppDiscoveryIq request; request.setType(QXmppIq::Get); request.setQueryType(QXmppDiscoveryIq::ItemsQuery); request.setTo(jid); if(!node.isEmpty()) request.setQueryNode(node); if(client()->sendPacket(request)) return request.id(); else return QString(); } /// Returns the client's full capabilities. QXmppDiscoveryIq QXmppDiscoveryManager::capabilities() { QXmppDiscoveryIq iq; iq.setType(QXmppIq::Result); iq.setQueryType(QXmppDiscoveryIq::InfoQuery); // features QStringList features; features << ns_data // XEP-0004: Data Forms << ns_rsm // XEP-0059: Result Set Management << ns_xhtml_im // XEP-0071: XHTML-IM << ns_chat_states // XEP-0085: Chat State Notifications << ns_capabilities // XEP-0115: Entity Capabilities << ns_ping // XEP-0199: XMPP Ping << ns_attention // XEP-0224: Attention << ns_chat_markers; // XEP-0333: Chat Markers foreach(QXmppClientExtension* extension, client()->extensions()) { if(extension) features << extension->discoveryFeatures(); } iq.setFeatures(features); // identities QList identities; QXmppDiscoveryIq::Identity identity; identity.setCategory(clientCategory()); identity.setType(clientType()); identity.setName(clientName()); identities << identity; foreach(QXmppClientExtension* extension, client()->extensions()) { if(extension) identities << extension->discoveryIdentities(); } iq.setIdentities(identities); // extended information if (!d->clientInfoForm.isNull()) iq.setForm(d->clientInfoForm); return iq; } /// Sets the capabilities node of the local XMPP client. /// /// \param node void QXmppDiscoveryManager::setClientCapabilitiesNode(const QString &node) { d->clientCapabilitiesNode = node; } /// Sets the category of the local XMPP client. /// /// You can find a list of valid categories at: /// http://xmpp.org/registrar/disco-categories.html /// /// \param category void QXmppDiscoveryManager::setClientCategory(const QString& category) { d->clientCategory = category; } /// Sets the type of the local XMPP client. /// /// You can find a list of valid types at: /// http://xmpp.org/registrar/disco-categories.html /// /// \param type void QXmppDiscoveryManager::setClientType(const QString& type) { d->clientType = type; } /// Sets the name of the local XMPP client. /// /// \param name void QXmppDiscoveryManager::setClientName(const QString& name) { d->clientName = name; } /// Returns the capabilities node of the local XMPP client. /// /// By default this is "https://github.com/qxmpp-project/qxmpp". QString QXmppDiscoveryManager::clientCapabilitiesNode() const { return d->clientCapabilitiesNode; } /// Returns the category of the local XMPP client. /// /// By default this is "client". QString QXmppDiscoveryManager::clientCategory() const { return d->clientCategory; } /// Returns the type of the local XMPP client. /// /// By default this is "pc". QString QXmppDiscoveryManager::clientType() const { return d->clientType; } /// Returns the name of the local XMPP client. /// /// By default this is "Based on QXmpp x.y.z". QString QXmppDiscoveryManager::clientName() const { return d->clientName; } /// Returns the client's extended information form, as defined /// by XEP-0128 Service Discovery Extensions. QXmppDataForm QXmppDiscoveryManager::clientInfoForm() const { return d->clientInfoForm; } /// Sets the client's extended information form, as defined /// by XEP-0128 Service Discovery Extensions. void QXmppDiscoveryManager::setClientInfoForm(const QXmppDataForm &form) { d->clientInfoForm = form; } /// \cond QStringList QXmppDiscoveryManager::discoveryFeatures() const { return QStringList() << ns_disco_info; } bool QXmppDiscoveryManager::handleStanza(const QDomElement &element) { if (element.tagName() == "iq" && QXmppDiscoveryIq::isDiscoveryIq(element)) { QXmppDiscoveryIq receivedIq; receivedIq.parse(element); switch (receivedIq.type()) { case QXmppIq::Get: if (receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery && (receivedIq.queryNode().isEmpty() || receivedIq.queryNode().startsWith(d->clientCapabilitiesNode))) { // respond to info queries for the client itself QXmppDiscoveryIq qxmppFeatures = capabilities(); qxmppFeatures.setId(receivedIq.id()); qxmppFeatures.setTo(receivedIq.from()); qxmppFeatures.setQueryNode(receivedIq.queryNode()); client()->sendPacket(qxmppFeatures); return true; } else { // let other managers handle other queries return false; } case QXmppIq::Result: case QXmppIq::Error: // handle all replies if (receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery) { emit infoReceived(receivedIq); } else if (receivedIq.queryType() == QXmppDiscoveryIq::ItemsQuery) { emit itemsReceived(receivedIq); } return true; case QXmppIq::Set: // let other manager handle "set" IQs return false; } } return false; } /// \endcond qxmpp-0.9.3/src/client/QXmppDiscoveryManager.h000066400000000000000000000045001263006255200213360ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 QXMPPDISCOVERYMANAGER_H #define QXMPPDISCOVERYMANAGER_H #include "QXmppClientExtension.h" class QXmppDataForm; class QXmppDiscoveryIq; class QXmppDiscoveryManagerPrivate; /// \brief The QXmppDiscoveryManager class makes it possible to discover information /// about other entities as defined by XEP-0030: Service Discovery. /// /// \ingroup Managers class QXMPP_EXPORT QXmppDiscoveryManager : public QXmppClientExtension { Q_OBJECT public: QXmppDiscoveryManager(); ~QXmppDiscoveryManager(); QXmppDiscoveryIq capabilities(); QString requestInfo(const QString& jid, const QString& node = QString()); QString requestItems(const QString& jid, const QString& node = QString()); QString clientCapabilitiesNode() const; void setClientCapabilitiesNode(const QString&); // http://xmpp.org/registrar/disco-categories.html#client QString clientCategory() const; void setClientCategory(const QString&); void setClientName(const QString&); QString clientName() const; QString clientType() const; void setClientType(const QString&); QXmppDataForm clientInfoForm() const; void setClientInfoForm(const QXmppDataForm &form); /// \cond QStringList discoveryFeatures() const; bool handleStanza(const QDomElement &element); /// \endcond signals: /// This signal is emitted when an information response is received. void infoReceived(const QXmppDiscoveryIq&); /// This signal is emitted when an items response is received. void itemsReceived(const QXmppDiscoveryIq&); private: QXmppDiscoveryManagerPrivate *d; }; #endif // QXMPPDISCOVERYMANAGER_H qxmpp-0.9.3/src/client/QXmppEntityTimeManager.cpp000066400000000000000000000043351263006255200220230ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppEntityTimeManager.h" #include #include #include "QXmppClient.h" #include "QXmppConstants.h" #include "QXmppEntityTimeIq.h" #include "QXmppUtils.h" /// Request the time from an XMPP entity. /// /// \param jid QString QXmppEntityTimeManager::requestTime(const QString& jid) { QXmppEntityTimeIq request; request.setType(QXmppIq::Get); request.setTo(jid); if(client()->sendPacket(request)) return request.id(); else return QString(); } /// \cond QStringList QXmppEntityTimeManager::discoveryFeatures() const { return QStringList() << ns_entity_time; } bool QXmppEntityTimeManager::handleStanza(const QDomElement &element) { if(element.tagName() == "iq" && QXmppEntityTimeIq::isEntityTimeIq(element)) { QXmppEntityTimeIq entityTime; entityTime.parse(element); if(entityTime.type() == QXmppIq::Get) { // respond to query QXmppEntityTimeIq responseIq; responseIq.setType(QXmppIq::Result); responseIq.setId(entityTime.id()); responseIq.setTo(entityTime.from()); QDateTime currentTime = QDateTime::currentDateTime(); QDateTime utc = currentTime.toUTC(); responseIq.setUtc(utc); currentTime.setTimeSpec(Qt::UTC); responseIq.setTzo(utc.secsTo(currentTime)); client()->sendPacket(responseIq); } emit timeReceived(entityTime); return true; } return false; } /// \endcond qxmpp-0.9.3/src/client/QXmppEntityTimeManager.h000066400000000000000000000026551263006255200214730ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 QXMPPENTITYTIMEMANAGER_H #define QXMPPENTITYTIMEMANAGER_H #include "QXmppClientExtension.h" class QXmppEntityTimeIq; /// \brief The QXmppEntityTimeManager class provided the functionality to get /// the local time of an entity as defined by XEP-0202: Entity Time. /// /// \ingroup Managers class QXMPP_EXPORT QXmppEntityTimeManager : public QXmppClientExtension { Q_OBJECT public: QString requestTime(const QString& jid); /// \cond QStringList discoveryFeatures() const; bool handleStanza(const QDomElement &element); /// \endcond signals: /// \brief This signal is emitted when a time response is received. void timeReceived(const QXmppEntityTimeIq&); }; #endif // QXMPPENTITYTIMEMANAGER_H qxmpp-0.9.3/src/client/QXmppInvokable.cpp000066400000000000000000000106071263006255200203460ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Ian Reinhart Geiser * * Source: * https://github.com/qxmpp-project/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 "QXmppInvokable.h" #include #include #include #include /// Constructs a QXmppInvokable with the specified \a parent. /// /// \param parent QXmppInvokable::QXmppInvokable(QObject *parent) : QObject(parent) { } /// Destroys a QXmppInvokable. QXmppInvokable::~QXmppInvokable() { } QVariant QXmppInvokable::dispatch( const QByteArray & method, const QList< QVariant > & args ) { buildMethodHash(); if( !m_methodHash.contains(method)) return QVariant(); int idx = m_methodHash[method]; if( paramTypes( args) != metaObject()->method(idx).parameterTypes ()) return QVariant(); const char *typeName = metaObject()->method(idx).typeName(); int resultType = QMetaType::type(typeName); #if QT_VERSION >= 0x050000 void *result = QMetaType::create(resultType, 0); #else void *result = QMetaType::construct(resultType, 0); #endif QGenericReturnArgument ret( typeName, result ); QList genericArgs; QList::ConstIterator iter = args.begin(); while( iter != args.end()) { const void *data = iter->data(); const char *name = iter->typeName(); genericArgs << QGenericArgument(name,data); ++iter; } if( QMetaObject::invokeMethod ( this, method.constData(), ret, genericArgs.value(0, QGenericArgument() ), genericArgs.value(1, QGenericArgument() ), genericArgs.value(2, QGenericArgument() ), genericArgs.value(3, QGenericArgument() ), genericArgs.value(4, QGenericArgument() ), genericArgs.value(5, QGenericArgument() ), genericArgs.value(6, QGenericArgument() ), genericArgs.value(7, QGenericArgument() ), genericArgs.value(8, QGenericArgument() ), genericArgs.value(9, QGenericArgument() )) ) { QVariant returnValue( resultType, result); QMetaType::destroy(resultType, result); return returnValue; } else { qDebug("No such method '%s'", method.constData() ); return QVariant(); } } QList< QByteArray > QXmppInvokable::paramTypes( const QList< QVariant > & params ) { QList types; foreach( QVariant variant, params) types << variant.typeName(); return types; } void QXmppInvokable::buildMethodHash( ) { QWriteLocker locker(&m_lock); if( m_methodHash.size() > 0 ) return; int methodCount = metaObject()->methodCount (); for( int idx = 0; idx < methodCount; ++idx) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) QByteArray signature = metaObject()->method(idx).methodSignature(); #else QByteArray signature = metaObject()->method(idx).signature(); #endif m_methodHash[signature.left(signature.indexOf('('))] = idx; // qDebug() << metaObject()->method(idx).parameterTypes(); } } QStringList QXmppInvokable::interfaces( ) const { QStringList results; int methodCount = metaObject()->methodCount (); for( int idx = 0; idx < methodCount; ++idx) { if( metaObject()->method(idx).methodType() == QMetaMethod::Slot ) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) QByteArray signature = metaObject()->method(idx).methodSignature(); #else QByteArray signature = metaObject()->method(idx).signature(); #endif results << signature.left(signature.indexOf('(')); } } return results; } qxmpp-0.9.3/src/client/QXmppInvokable.h000066400000000000000000000047141263006255200200150ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Ian Reinhart Geiser * * Source: * https://github.com/qxmpp-project/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 QXMPPINVOKABLE_H #define QXMPPINVOKABLE_H #include #include #include #include #include #include "QXmppGlobal.h" /** This is the base class for all objects that will be invokable via RPC. All public slots of objects derived from this class will be exposed to the RPC interface. As a note for all methods, they can only understand types that QVariant knows about. @author Ian Reinhart Geiser */ class QXMPP_EXPORT QXmppInvokable : public QObject { Q_OBJECT public: QXmppInvokable( QObject *parent = 0 ); ~QXmppInvokable(); /** * Execute a method on an object. with a set of arguments. This method is reentrant, and the method * that is invoked will be done in a thread safe manner. It should be noted that while this method * is threadsafe and reentrant the side affects of the methods invoked may not be. */ QVariant dispatch( const QByteArray &method, const QList &args = QList() ); /** * Utility method to convert a QList to a list of types for type * checking. */ static QList paramTypes( const QList ¶ms ); /** * Reimplement this method to return a true if the invoking JID is allowed to execute the method. */ virtual bool isAuthorized( const QString &jid ) const = 0; public slots: /** * This provides a list of interfaces for introspection of the presented interface. */ QStringList interfaces() const; private: void buildMethodHash(); QHash m_methodHash; QReadWriteLock m_lock; }; #endif qxmpp-0.9.3/src/client/QXmppMessageReceiptManager.cpp000066400000000000000000000036421263006255200226300ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Georg Rudoy * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppMessageReceiptManager.h" #include #include "QXmppConstants.h" #include "QXmppMessage.h" #include "QXmppClient.h" /// Constructs a QXmppMessageReceiptManager to handle incoming and outgoing /// message delivery receipts. QXmppMessageReceiptManager::QXmppMessageReceiptManager() : QXmppClientExtension() { } /// \cond QStringList QXmppMessageReceiptManager::discoveryFeatures() const { return QStringList(ns_message_receipts); } bool QXmppMessageReceiptManager::handleStanza(const QDomElement &stanza) { if (stanza.tagName() != "message") return false; QXmppMessage message; message.parse(stanza); // Handle receipts and cancel any further processing. if (!message.receiptId().isEmpty()) { emit messageDelivered(message.from(), message.receiptId()); return true; } // If requested, send a receipt. if (message.isReceiptRequested() && !message.from().isEmpty() && !message.id().isEmpty()) { QXmppMessage receipt; receipt.setTo(message.from()); receipt.setReceiptId(message.id()); client()->sendPacket(receipt); } // Continue processing. return false; } /// \endcond qxmpp-0.9.3/src/client/QXmppMessageReceiptManager.h000066400000000000000000000031041263006255200222660ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Georg Rudoy * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPMESSAGERECEIPTMANAGER_H #define QXMPPMESSAGERECEIPTMANAGER_H #include "QXmppClientExtension.h" /// \brief The QXmppMessageReceiptManager class makes it possible to /// send and receive message delivery receipts as defined in /// XEP-0184: Message Delivery Receipts. /// /// \ingroup Managers class QXMPP_EXPORT QXmppMessageReceiptManager : public QXmppClientExtension { Q_OBJECT public: QXmppMessageReceiptManager(); /// \cond virtual QStringList discoveryFeatures() const; virtual bool handleStanza(const QDomElement &stanza); /// \endcond signals: /// This signal is emitted when receipt for the message with the /// given id is received. The id could be previously obtained by /// calling QXmppMessage::id(). void messageDelivered(const QString &jid, const QString &id); }; #endif // QXMPPMESSAGERECEIPTMANAGER_H qxmpp-0.9.3/src/client/QXmppMucManager.cpp000066400000000000000000000457441263006255200204650ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppClient.h" #include "QXmppConstants.h" #include "QXmppDiscoveryManager.h" #include "QXmppMessage.h" #include "QXmppMucIq.h" #include "QXmppMucManager.h" #include "QXmppUtils.h" class QXmppMucManagerPrivate { public: QMap rooms; }; class QXmppMucRoomPrivate { public: QString ownJid() const { return jid + "/" + nickName; } QXmppClient *client; QXmppDiscoveryManager *discoManager; QXmppMucRoom::Actions allowedActions; QString jid; QString name; QMap participants; QString password; QMap permissions; QSet permissionsQueue; QString nickName; QString subject; }; /// Constructs a new QXmppMucManager. QXmppMucManager::QXmppMucManager() { d = new QXmppMucManagerPrivate; } /// Destroys a QXmppMucManager. QXmppMucManager::~QXmppMucManager() { delete d; } /// Adds the given chat room to the set of managed rooms. /// /// \param roomJid QXmppMucRoom *QXmppMucManager::addRoom(const QString &roomJid) { QXmppMucRoom *room = d->rooms.value(roomJid); if (!room) { room = new QXmppMucRoom(client(), roomJid, this); d->rooms.insert(roomJid, room); connect(room, SIGNAL(destroyed(QObject*)), this, SLOT(_q_roomDestroyed(QObject*))); // emit signal emit roomAdded(room); } return room; } /// Returns the list of managed rooms. QList QXmppMucManager::rooms() const { return d->rooms.values(); } /// \cond QStringList QXmppMucManager::discoveryFeatures() const { // XEP-0045: Multi-User Chat return QStringList() << ns_muc << ns_muc_admin << ns_muc_owner << ns_muc_user << ns_conference; } bool QXmppMucManager::handleStanza(const QDomElement &element) { if (element.tagName() == "iq") { if (QXmppMucAdminIq::isMucAdminIq(element)) { QXmppMucAdminIq iq; iq.parse(element); QXmppMucRoom *room = d->rooms.value(iq.from()); if (room && iq.type() == QXmppIq::Result && room->d->permissionsQueue.remove(iq.id())) { foreach (const QXmppMucItem &item, iq.items()) { const QString jid = item.jid(); if (!room->d->permissions.contains(jid)) room->d->permissions.insert(jid, item); } if (room->d->permissionsQueue.isEmpty()) { emit room->permissionsReceived(room->d->permissions.values()); } } return true; } else if (QXmppMucOwnerIq::isMucOwnerIq(element)) { QXmppMucOwnerIq iq; iq.parse(element); QXmppMucRoom *room = d->rooms.value(iq.from()); if (room && iq.type() == QXmppIq::Result && !iq.form().isNull()) emit room->configurationReceived(iq.form()); return true; } } return false; } void QXmppMucManager::setClient(QXmppClient* client) { bool check; Q_UNUSED(check); QXmppClientExtension::setClient(client); check = connect(client, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(_q_messageReceived(QXmppMessage))); Q_ASSERT(check); } /// \endcond void QXmppMucManager::_q_messageReceived(const QXmppMessage &msg) { if (msg.type() != QXmppMessage::Normal) return; // process room invitations const QString roomJid = msg.mucInvitationJid(); if (!roomJid.isEmpty() && (!d->rooms.contains(roomJid) || !d->rooms.value(roomJid)->isJoined())) { emit invitationReceived(roomJid, msg.from(), msg.mucInvitationReason()); } } void QXmppMucManager::_q_roomDestroyed(QObject *object) { const QString key = d->rooms.key(static_cast(object)); d->rooms.remove(key); } /// Constructs a new QXmppMucRoom. /// /// \param parent QXmppMucRoom::QXmppMucRoom(QXmppClient *client, const QString &jid, QObject *parent) : QObject(parent) { bool check; Q_UNUSED(check); d = new QXmppMucRoomPrivate; d->allowedActions = NoAction; d->client = client; d->discoManager = client->findExtension(); d->jid = jid; check = connect(d->client, SIGNAL(disconnected()), this, SLOT(_q_disconnected())); Q_ASSERT(check); check = connect(d->client, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(_q_messageReceived(QXmppMessage))); Q_ASSERT(check); check = connect(d->client, SIGNAL(presenceReceived(QXmppPresence)), this, SLOT(_q_presenceReceived(QXmppPresence))); Q_ASSERT(check); if (d->discoManager) { check = connect(d->discoManager, SIGNAL(infoReceived(QXmppDiscoveryIq)), this, SLOT(_q_discoveryInfoReceived(QXmppDiscoveryIq))); Q_ASSERT(check); } // convenience signals for properties check = connect(this, SIGNAL(joined()), this, SIGNAL(isJoinedChanged())); Q_ASSERT(check); check = connect(this, SIGNAL(left()), this, SIGNAL(isJoinedChanged())); Q_ASSERT(check); } /// Destroys a QXmppMucRoom. QXmppMucRoom::~QXmppMucRoom() { delete d; } /// Returns the actions you are allowed to perform on the room. QXmppMucRoom::Actions QXmppMucRoom::allowedActions() const { return d->allowedActions; } /// Bans the specified user from the chat room. /// /// The specified \a jid is the Bare JID of the form "user@host". /// /// \return true if the request was sent, false otherwise bool QXmppMucRoom::ban(const QString &jid, const QString &reason) { if (!QXmppUtils::jidToResource(jid).isEmpty()) { qWarning("QXmppMucRoom::ban expects a bare JID"); return false; } QXmppMucItem item; item.setAffiliation(QXmppMucItem::OutcastAffiliation); item.setJid(jid); item.setReason(reason); QXmppMucAdminIq iq; iq.setType(QXmppIq::Set); iq.setTo(d->jid); iq.setItems(QList() << item); return d->client->sendPacket(iq); } /// Returns true if you are currently in the room. bool QXmppMucRoom::isJoined() const { return d->participants.contains(d->ownJid()); } /// Returns the chat room's bare JID. QString QXmppMucRoom::jid() const { return d->jid; } /// Joins the chat room. /// /// \return true if the request was sent, false otherwise bool QXmppMucRoom::join() { if (isJoined() || d->nickName.isEmpty()) return false; // reflect our current presence in the chat room QXmppPresence packet = d->client->clientPresence(); packet.setTo(d->ownJid()); packet.setType(QXmppPresence::Available); packet.setMucPassword(d->password); packet.setMucSupported(true); return d->client->sendPacket(packet); } /// Kicks the specified user from the chat room. /// /// The specified \a jid is the Occupant JID of the form "room@service/nick". /// /// \return true if the request was sent, false otherwise bool QXmppMucRoom::kick(const QString &jid, const QString &reason) { QXmppMucItem item; item.setNick(QXmppUtils::jidToResource(jid)); item.setRole(QXmppMucItem::NoRole); item.setReason(reason); QXmppMucAdminIq iq; iq.setType(QXmppIq::Set); iq.setTo(d->jid); iq.setItems(QList() << item); return d->client->sendPacket(iq); } /// Leaves the chat room. /// /// \param message An optional message. /// /// \return true if the request was sent, false otherwise bool QXmppMucRoom::leave(const QString &message) { QXmppPresence packet; packet.setTo(d->ownJid()); packet.setType(QXmppPresence::Unavailable); packet.setStatusText(message); return d->client->sendPacket(packet); } /// Returns the chat room's human-readable name. /// /// This name will only be available after the room has been joined. QString QXmppMucRoom::name() const { return d->name; } /// Returns your own nickname. QString QXmppMucRoom::nickName() const { return d->nickName; } /// Invites a user to the chat room. /// /// \param jid /// \param reason /// /// \return true if the request was sent, false otherwise bool QXmppMucRoom::sendInvitation(const QString &jid, const QString &reason) { QXmppMessage message; message.setTo(jid); message.setType(QXmppMessage::Normal); message.setMucInvitationJid(d->jid); message.setMucInvitationReason(reason); return d->client->sendPacket(message); } /// Sends a message to the room. /// /// \return true if the request was sent, false otherwise bool QXmppMucRoom::sendMessage(const QString &text) { QXmppMessage msg; msg.setTo(d->jid); msg.setType(QXmppMessage::GroupChat); msg.setBody(text); return d->client->sendPacket(msg); } /// Sets your own nickname. /// /// You need to set your nickname before calling join(). /// /// \param nickName void QXmppMucRoom::setNickName(const QString &nickName) { if (nickName == d->nickName) return; // if we had already joined the room, request nickname change if (isJoined()) { QXmppPresence packet = d->client->clientPresence(); packet.setTo(d->jid + "/" + nickName); packet.setType(QXmppPresence::Available); d->client->sendPacket(packet); } else { d->nickName = nickName; emit nickNameChanged(nickName); } } /// Returns the "Full JID" of the given participant. /// /// The specified \a jid is the Occupant JID of the form "room@service/nick". QString QXmppMucRoom::participantFullJid(const QString &jid) const { if (d->participants.contains(jid)) return d->participants.value(jid).mucItem().jid(); else return QString(); } /// Returns the presence for the given participant. /// /// The specified \a jid is the Occupant JID of the form "room@service/nick". QXmppPresence QXmppMucRoom::participantPresence(const QString &jid) const { if (d->participants.contains(jid)) return d->participants.value(jid); QXmppPresence presence; presence.setFrom(jid); presence.setType(QXmppPresence::Unavailable); return presence; } /// Returns the list of participant JIDs. /// /// These JIDs are Occupant JIDs of the form "room@service/nick". QStringList QXmppMucRoom::participants() const { return d->participants.keys(); } /// Returns the chat room password. QString QXmppMucRoom::password() const { return d->password; } /// Sets the chat room password. /// /// \param password void QXmppMucRoom::setPassword(const QString &password) { d->password = password; } /// Returns the room's subject. QString QXmppMucRoom::subject() const { return d->subject; } /// Sets the chat room's subject. /// /// \param subject void QXmppMucRoom::setSubject(const QString &subject) { QXmppMessage msg; msg.setTo(d->jid); msg.setType(QXmppMessage::GroupChat); msg.setSubject(subject); d->client->sendPacket(msg); } /// Request the configuration form for the chat room. /// /// \return true if the request was sent, false otherwise /// /// \sa configurationReceived() bool QXmppMucRoom::requestConfiguration() { QXmppMucOwnerIq iq; iq.setTo(d->jid); return d->client->sendPacket(iq); } /// Send the configuration form for the chat room. /// /// \param form /// /// \return true if the request was sent, false otherwise bool QXmppMucRoom::setConfiguration(const QXmppDataForm &form) { QXmppMucOwnerIq iqPacket; iqPacket.setType(QXmppIq::Set); iqPacket.setTo(d->jid); iqPacket.setForm(form); return d->client->sendPacket(iqPacket); } /// Request the room's permissions. /// /// \return true if the request was sent, false otherwise /// /// \sa permissionsReceived() bool QXmppMucRoom::requestPermissions() { QList affiliations; affiliations << QXmppMucItem::OwnerAffiliation; affiliations << QXmppMucItem::AdminAffiliation; affiliations << QXmppMucItem::MemberAffiliation; affiliations << QXmppMucItem::OutcastAffiliation; d->permissions.clear(); d->permissionsQueue.clear(); foreach (QXmppMucItem::Affiliation affiliation, affiliations) { QXmppMucItem item; item.setAffiliation(affiliation); QXmppMucAdminIq iq; iq.setTo(d->jid); iq.setItems(QList() << item); if (!d->client->sendPacket(iq)) return false; d->permissionsQueue += iq.id(); } return true; } /// Sets the room's permissions. /// /// \param permissions /// /// \return true if the request was sent, false otherwise bool QXmppMucRoom::setPermissions(const QList &permissions) { QList items; // Process changed members foreach (const QXmppMucItem &item, permissions) { const QString jid = item.jid(); if (d->permissions.value(jid).affiliation() != item.affiliation()) items << item; d->permissions.remove(jid); } // Process deleted members foreach (const QString &jid, d->permissions.keys()) { QXmppMucItem item; item.setAffiliation(QXmppMucItem::NoAffiliation); item.setJid(jid); items << item; d->permissions.remove(jid); } // Don't send request if there are no changes if (items.isEmpty()) return false; QXmppMucAdminIq iq; iq.setTo(d->jid); iq.setType(QXmppIq::Set); iq.setItems(items); return d->client->sendPacket(iq); } void QXmppMucRoom::_q_disconnected() { const bool wasJoined = isJoined(); // clear chat room participants const QStringList removed = d->participants.keys(); d->participants.clear(); foreach (const QString &jid, removed) emit participantRemoved(jid); emit participantsChanged(); // update available actions if (d->allowedActions != NoAction) { d->allowedActions = NoAction; emit allowedActionsChanged(d->allowedActions); } // emit "left" signal if we had joined the room if (wasJoined) emit left(); } void QXmppMucRoom::_q_discoveryInfoReceived(const QXmppDiscoveryIq &iq) { if (iq.from() == d->jid) { QString name; foreach (const QXmppDiscoveryIq::Identity &identity, iq.identities()) { if (identity.category() == "conference") { name = identity.name(); break; } } if (name != d->name) { d->name = name; emit nameChanged(name); } } } void QXmppMucRoom::_q_messageReceived(const QXmppMessage &message) { if (QXmppUtils::jidToBareJid(message.from())!= d->jid) return; // handle message subject const QString subject = message.subject(); if (!subject.isEmpty()) { d->subject = subject; emit subjectChanged(subject); } emit messageReceived(message); } void QXmppMucRoom::_q_presenceReceived(const QXmppPresence &presence) { const QString jid = presence.from(); // if our own presence changes, reflect it in the chat room if (isJoined() && jid == d->client->configuration().jid()) { QXmppPresence packet = d->client->clientPresence(); packet.setTo(d->ownJid()); d->client->sendPacket(packet); } if (QXmppUtils::jidToBareJid(jid) != d->jid) return; if (presence.type() == QXmppPresence::Available) { const bool added = !d->participants.contains(jid); d->participants.insert(jid, presence); // refresh allowed actions if (jid == d->ownJid()) { QXmppMucItem mucItem = presence.mucItem(); Actions newActions = NoAction; // role if (mucItem.role() == QXmppMucItem::ModeratorRole) newActions |= (KickAction | SubjectAction); // affiliation if (mucItem.affiliation() == QXmppMucItem::OwnerAffiliation) newActions |= (ConfigurationAction | PermissionsAction | SubjectAction); else if (mucItem.affiliation() == QXmppMucItem::AdminAffiliation) newActions |= (PermissionsAction | SubjectAction); if (newActions != d->allowedActions) { d->allowedActions = newActions; emit allowedActionsChanged(d->allowedActions); } } if (added) { emit participantAdded(jid); emit participantsChanged(); if (jid == d->ownJid()) { // request room information if (d->discoManager) d->discoManager->requestInfo(d->jid); emit joined(); } } else { emit participantChanged(jid); } } else if (presence.type() == QXmppPresence::Unavailable) { if (d->participants.contains(jid)) { d->participants.insert(jid, presence); emit participantRemoved(jid); d->participants.remove(jid); emit participantsChanged(); // check whether this was our own presence if (jid == d->ownJid()) { const QString newNick = presence.mucItem().nick(); if (!newNick.isEmpty() && newNick != d->nickName) { d->nickName = newNick; emit nickNameChanged(newNick); return; } // check whether we were kicked if (presence.mucStatusCodes().contains(307)) { const QString actor = presence.mucItem().actor(); const QString reason = presence.mucItem().reason(); emit kicked(actor, reason); } // clear chat room participants const QStringList removed = d->participants.keys(); d->participants.clear(); foreach (const QString &jid, removed) emit participantRemoved(jid); emit participantsChanged(); // update available actions if (d->allowedActions != NoAction) { d->allowedActions = NoAction; emit allowedActionsChanged(d->allowedActions); } // notify user we left the room emit left(); } } } else if (presence.type() == QXmppPresence::Error) { if (presence.isMucSupported()) { // emit error emit error(presence.error()); // notify the user we left the room emit left(); } } } qxmpp-0.9.3/src/client/QXmppMucManager.h000066400000000000000000000156501263006255200201230ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPMUCMANAGER_H #define QXMPPMUCMANAGER_H #include "QXmppClientExtension.h" #include "QXmppMucIq.h" #include "QXmppPresence.h" class QXmppDataForm; class QXmppDiscoveryIq; class QXmppMessage; class QXmppMucManagerPrivate; class QXmppMucRoom; class QXmppMucRoomPrivate; /// \brief The QXmppMucManager class makes it possible to interact with /// multi-user chat rooms as defined by XEP-0045: Multi-User Chat. /// /// To make use of this manager, you need to instantiate it and load it into /// the QXmppClient instance as follows: /// /// \code /// QXmppMucManager *manager = new QXmppMucManager; /// client->addExtension(manager); /// \endcode /// /// You can then join a room as follows: /// /// \code /// QXmppMucRoom *room = manager->addRoom("room@conference.example.com"); /// room->setNickName("mynick"); /// room->join(); /// \endcode /// /// \ingroup Managers class QXMPP_EXPORT QXmppMucManager : public QXmppClientExtension { Q_OBJECT Q_PROPERTY(QList rooms READ rooms NOTIFY roomAdded) public: QXmppMucManager(); ~QXmppMucManager(); QXmppMucRoom *addRoom(const QString &roomJid); QList rooms() const; /// \cond QStringList discoveryFeatures() const; bool handleStanza(const QDomElement &element); /// \endcond signals: /// This signal is emitted when an invitation to a chat room is received. void invitationReceived(const QString &roomJid, const QString &inviter, const QString &reason); /// This signal is emitted when a new room is managed. void roomAdded(QXmppMucRoom *room); protected: /// \cond void setClient(QXmppClient* client); /// \endcond private slots: void _q_messageReceived(const QXmppMessage &message); void _q_roomDestroyed(QObject *object); private: QXmppMucManagerPrivate *d; }; /// \brief The QXmppMucRoom class represents a multi-user chat room /// as defined by XEP-0045: Multi-User Chat. /// /// \sa QXmppMucManager class QXMPP_EXPORT QXmppMucRoom : public QObject { Q_OBJECT Q_FLAGS(Action Actions) Q_PROPERTY(QXmppMucRoom::Actions allowedActions READ allowedActions NOTIFY allowedActionsChanged) Q_PROPERTY(bool isJoined READ isJoined NOTIFY isJoinedChanged) Q_PROPERTY(QString jid READ jid CONSTANT) Q_PROPERTY(QString name READ name NOTIFY nameChanged) Q_PROPERTY(QString nickName READ nickName WRITE setNickName NOTIFY nickNameChanged) Q_PROPERTY(QStringList participants READ participants NOTIFY participantsChanged) Q_PROPERTY(QString password READ password WRITE setPassword) Q_PROPERTY(QString subject READ subject WRITE setSubject NOTIFY subjectChanged) public: /// This enum is used to describe chat room actions. enum Action { NoAction = 0, ///< no action SubjectAction = 1, ///< change the room's subject ConfigurationAction = 2, ///< change the room's configuration PermissionsAction = 4, ///< change the room's permissions KickAction = 8 ///< kick users from the room }; Q_DECLARE_FLAGS(Actions, Action) ~QXmppMucRoom(); Actions allowedActions() const; bool isJoined() const; QString jid() const; QString name() const; QString nickName() const; void setNickName(const QString &nickName); Q_INVOKABLE QString participantFullJid(const QString &jid) const; QXmppPresence participantPresence(const QString &jid) const; QStringList participants() const; QString password() const; void setPassword(const QString &password); QString subject() const; void setSubject(const QString &subject); signals: /// This signal is emitted when the allowed actions change. void allowedActionsChanged(QXmppMucRoom::Actions actions) const; /// This signal is emitted when the configuration form for the room is received. void configurationReceived(const QXmppDataForm &configuration); /// This signal is emitted when an error is encountered. void error(const QXmppStanza::Error &error); /// This signal is emitted once you have joined the room. void joined(); /// This signal is emitted if you get kicked from the room. void kicked(const QString &jid, const QString &reason); /// \cond void isJoinedChanged(); /// \endcond /// This signal is emitted once you have left the room. void left(); /// This signal is emitted when a message is received. void messageReceived(const QXmppMessage &message); /// This signal is emitted when the room's human-readable name changes. void nameChanged(const QString &name); /// This signal is emitted when your own nick name changes. void nickNameChanged(const QString &nickName); /// This signal is emitted when a participant joins the room. void participantAdded(const QString &jid); /// This signal is emitted when a participant changes. void participantChanged(const QString &jid); /// This signal is emitted when a participant leaves the room. void participantRemoved(const QString &jid); /// \cond void participantsChanged(); /// \endcond /// This signal is emitted when the room's permissions are received. void permissionsReceived(const QList &permissions); /// This signal is emitted when the room's subject changes. void subjectChanged(const QString &subject); public slots: bool ban(const QString &jid, const QString &reason); bool join(); bool kick(const QString &jid, const QString &reason); bool leave(const QString &message = QString()); bool requestConfiguration(); bool requestPermissions(); bool setConfiguration(const QXmppDataForm &form); bool setPermissions(const QList &permissions); bool sendInvitation(const QString &jid, const QString &reason); bool sendMessage(const QString &text); private slots: void _q_disconnected(); void _q_discoveryInfoReceived(const QXmppDiscoveryIq &iq); void _q_messageReceived(const QXmppMessage &message); void _q_presenceReceived(const QXmppPresence &presence); private: QXmppMucRoom(QXmppClient *client, const QString &jid, QObject *parent); QXmppMucRoomPrivate *d; friend class QXmppMucManager; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QXmppMucRoom::Actions) #endif qxmpp-0.9.3/src/client/QXmppOutgoingClient.cpp000066400000000000000000000614231263006255200213700ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #else #include "qdnslookup.h" #endif #include "QXmppConfiguration.h" #include "QXmppConstants.h" #include "QXmppIq.h" #include "QXmppLogger.h" #include "QXmppMessage.h" #include "QXmppPresence.h" #include "QXmppOutgoingClient.h" #include "QXmppStreamFeatures.h" #include "QXmppNonSASLAuth.h" #include "QXmppSasl_p.h" #include "QXmppUtils.h" // IQ types #include "QXmppBindIq.h" #include "QXmppPingIq.h" #include "QXmppSessionIq.h" #include #include #include #include #include #include #include #include class QXmppOutgoingClientPrivate { public: QXmppOutgoingClientPrivate(QXmppOutgoingClient *q); void connectToHost(const QString &host, quint16 port); // This object provides the configuration // required for connecting to the XMPP server. QXmppConfiguration config; QXmppStanza::Error::Condition xmppStreamError; // DNS QDnsLookup dns; // Stream QString streamId; QString streamFrom; QString streamVersion; // Redirection QString redirectHost; quint16 redirectPort; // Session QString bindId; QString sessionId; bool sessionAvailable; bool sessionStarted; // Authentication bool isAuthenticated; QString nonSASLAuthId; QXmppSaslClient *saslClient; // Timers QTimer *pingTimer; QTimer *timeoutTimer; private: QXmppOutgoingClient *q; }; QXmppOutgoingClientPrivate::QXmppOutgoingClientPrivate(QXmppOutgoingClient *qq) : redirectPort(0) , sessionAvailable(false) , sessionStarted(false) , isAuthenticated(false) , saslClient(0) , pingTimer(0) , timeoutTimer(0) , q(qq) { } void QXmppOutgoingClientPrivate::connectToHost(const QString &host, quint16 port) { q->info(QString("Connecting to %1:%2").arg(host, QString::number(port))); // override CA certificates if requested if (!config.caCertificates().isEmpty()) q->socket()->setCaCertificates(config.caCertificates()); // respect proxy q->socket()->setProxy(config.networkProxy()); #if (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) // set the name the SSL certificate should match q->socket()->setPeerVerifyName(config.domain()); #endif // connect to host const QXmppConfiguration::StreamSecurityMode localSecurity = q->configuration().streamSecurityMode(); if (localSecurity == QXmppConfiguration::LegacySSL) { if (!q->socket()->supportsSsl()) { q->warning("Not connecting as legacy SSL was requested, but SSL support is not available"); return; } q->socket()->connectToHostEncrypted(host, port); } else { q->socket()->connectToHost(host, port); } } /// Constructs an outgoing client stream. /// /// \param parent QXmppOutgoingClient::QXmppOutgoingClient(QObject *parent) : QXmppStream(parent), d(new QXmppOutgoingClientPrivate(this)) { bool check; Q_UNUSED(check); // initialise socket QSslSocket *socket = new QSslSocket(this); setSocket(socket); check = connect(socket, SIGNAL(disconnected()), this, SLOT(_q_socketDisconnected())); Q_ASSERT(check); check = connect(socket, SIGNAL(sslErrors(QList)), this, SLOT(socketSslErrors(QList))); Q_ASSERT(check); check = connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); Q_ASSERT(check); // DNS lookups check = connect(&d->dns, SIGNAL(finished()), this, SLOT(_q_dnsLookupFinished())); Q_ASSERT(check); // XEP-0199: XMPP Ping d->pingTimer = new QTimer(this); check = connect(d->pingTimer, SIGNAL(timeout()), this, SLOT(pingSend())); Q_ASSERT(check); d->timeoutTimer = new QTimer(this); d->timeoutTimer->setSingleShot(true); check = connect(d->timeoutTimer, SIGNAL(timeout()), this, SLOT(pingTimeout())); Q_ASSERT(check); check = connect(this, SIGNAL(connected()), this, SLOT(pingStart())); Q_ASSERT(check); check = connect(this, SIGNAL(disconnected()), this, SLOT(pingStop())); Q_ASSERT(check); } /// Destroys an outgoing client stream. QXmppOutgoingClient::~QXmppOutgoingClient() { delete d; } /// Returns a reference to the stream's configuration. QXmppConfiguration& QXmppOutgoingClient::configuration() { return d->config; } /// Attempts to connect to the XMPP server. void QXmppOutgoingClient::connectToHost() { // if an explicit host was provided, connect to it if (!d->config.host().isEmpty() && d->config.port()) { d->connectToHost(d->config.host(), d->config.port()); return; } // otherwise, lookup server const QString domain = configuration().domain(); debug(QString("Looking up server for domain %1").arg(domain)); d->dns.setName("_xmpp-client._tcp." + domain); d->dns.setType(QDnsLookup::SRV); d->dns.lookup(); } void QXmppOutgoingClient::_q_dnsLookupFinished() { if (d->dns.error() == QDnsLookup::NoError && !d->dns.serviceRecords().isEmpty()) { // take the first returned record d->connectToHost( d->dns.serviceRecords().first().target(), d->dns.serviceRecords().first().port()); } else { // as a fallback, use domain as the host name warning(QString("Lookup for domain %1 failed: %2") .arg(d->dns.name(), d->dns.errorString())); d->connectToHost(d->config.domain(), d->config.port()); } } /// Returns true if authentication has succeeded. bool QXmppOutgoingClient::isAuthenticated() const { return d->isAuthenticated; } /// Returns true if the socket is connected and a session has been started. bool QXmppOutgoingClient::isConnected() const { return QXmppStream::isConnected() && d->sessionStarted; } void QXmppOutgoingClient::_q_socketDisconnected() { debug("Socket disconnected"); d->isAuthenticated = false; if (!d->redirectHost.isEmpty() && d->redirectPort > 0) { d->connectToHost(d->redirectHost, d->redirectPort); d->redirectHost = QString(); d->redirectPort = 0; } else { emit disconnected(); } } void QXmppOutgoingClient::socketSslErrors(const QList &errors) { // log errors warning("SSL errors"); for(int i = 0; i< errors.count(); ++i) warning(errors.at(i).errorString()); // relay signal emit sslErrors(errors); // if configured, ignore the errors if (configuration().ignoreSslErrors()) socket()->ignoreSslErrors(); } void QXmppOutgoingClient::socketError(QAbstractSocket::SocketError socketError) { Q_UNUSED(socketError); emit error(QXmppClient::SocketError); } /// \cond void QXmppOutgoingClient::handleStart() { QXmppStream::handleStart(); // reset stream information d->streamId.clear(); d->streamFrom.clear(); d->streamVersion.clear(); // reset authentication step if (d->saslClient) { delete d->saslClient; d->saslClient = 0; } // reset session information d->bindId.clear(); d->sessionId.clear(); d->sessionAvailable = false; d->sessionStarted = false; // start stream QByteArray data = ""); sendData(data); } void QXmppOutgoingClient::handleStream(const QDomElement &streamElement) { if(d->streamId.isEmpty()) d->streamId = streamElement.attribute("id"); if (d->streamFrom.isEmpty()) d->streamFrom = streamElement.attribute("from"); if(d->streamVersion.isEmpty()) { d->streamVersion = streamElement.attribute("version"); // no version specified, signals XMPP Version < 1.0. // switch to old auth mechanism if enabled if(d->streamVersion.isEmpty() && configuration().useNonSASLAuthentication()) { sendNonSASLAuthQuery(); } } } void QXmppOutgoingClient::handleStanza(const QDomElement &nodeRecv) { // if we receive any kind of data, stop the timeout timer d->timeoutTimer->stop(); const QString ns = nodeRecv.namespaceURI(); // give client opportunity to handle stanza bool handled = false; emit elementReceived(nodeRecv, handled); if (handled) return; if(QXmppStreamFeatures::isStreamFeatures(nodeRecv)) { QXmppStreamFeatures features; features.parse(nodeRecv); if (!socket()->isEncrypted()) { // determine TLS mode to use const QXmppConfiguration::StreamSecurityMode localSecurity = configuration().streamSecurityMode(); const QXmppStreamFeatures::Mode remoteSecurity = features.tlsMode(); if (!socket()->supportsSsl() && (localSecurity == QXmppConfiguration::TLSRequired || remoteSecurity == QXmppStreamFeatures::Required)) { warning("Disconnecting as TLS is required, but SSL support is not available"); disconnectFromHost(); return; } if (localSecurity == QXmppConfiguration::TLSRequired && remoteSecurity == QXmppStreamFeatures::Disabled) { warning("Disconnecting as TLS is required, but not supported by the server"); disconnectFromHost(); return; } if (socket()->supportsSsl() && localSecurity != QXmppConfiguration::TLSDisabled && remoteSecurity != QXmppStreamFeatures::Disabled) { // enable TLS as it is support by both parties sendData(""); return; } } // handle authentication const bool nonSaslAvailable = features.nonSaslAuthMode() != QXmppStreamFeatures::Disabled; const bool saslAvailable = !features.authMechanisms().isEmpty(); if (saslAvailable && configuration().useSASLAuthentication()) { // supported and preferred SASL auth mechanisms QStringList supportedMechanisms = QXmppSaslClient::availableMechanisms(); const QString preferredMechanism = configuration().saslAuthMechanism(); if (configuration().facebookAppId().isEmpty() || configuration().facebookAccessToken().isEmpty()) supportedMechanisms.removeAll("X-FACEBOOK-PLATFORM"); if (configuration().windowsLiveAccessToken().isEmpty()) supportedMechanisms.removeAll("X-MESSENGER-OAUTH2"); if (configuration().googleAccessToken().isEmpty()) supportedMechanisms.removeAll("X-OAUTH2"); // determine SASL Authentication mechanism to use QStringList commonMechanisms; QString usedMechanism; foreach (const QString &mechanism, features.authMechanisms()) { if (supportedMechanisms.contains(mechanism)) commonMechanisms << mechanism; } if (commonMechanisms.isEmpty()) { warning("No supported SASL Authentication mechanism available"); disconnectFromHost(); return; } else if (!commonMechanisms.contains(preferredMechanism)) { info(QString("Desired SASL Auth mechanism '%1' is not available, selecting first available one").arg(preferredMechanism)); usedMechanism = commonMechanisms.first(); } else { usedMechanism = preferredMechanism; } d->saslClient = QXmppSaslClient::create(usedMechanism, this); if (!d->saslClient) { warning("SASL mechanism negotiation failed"); disconnectFromHost(); return; } info(QString("SASL mechanism '%1' selected").arg(d->saslClient->mechanism())); d->saslClient->setHost(d->config.domain()); d->saslClient->setServiceType("xmpp"); if (d->saslClient->mechanism() == "X-FACEBOOK-PLATFORM") { d->saslClient->setUsername(configuration().facebookAppId()); d->saslClient->setPassword(configuration().facebookAccessToken()); } else if (d->saslClient->mechanism() == "X-MESSENGER-OAUTH2") { d->saslClient->setPassword(configuration().windowsLiveAccessToken()); } else if (d->saslClient->mechanism() == "X-OAUTH2") { d->saslClient->setUsername(configuration().user()); d->saslClient->setPassword(configuration().googleAccessToken()); } else { d->saslClient->setUsername(configuration().user()); d->saslClient->setPassword(configuration().password()); } // send SASL auth request QByteArray response; if (!d->saslClient->respond(QByteArray(), response)) { warning("SASL initial response failed"); disconnectFromHost(); return; } sendPacket(QXmppSaslAuth(d->saslClient->mechanism(), response)); return; } else if(nonSaslAvailable && configuration().useNonSASLAuthentication()) { sendNonSASLAuthQuery(); return; } // store whether session is available d->sessionAvailable = (features.sessionMode() != QXmppStreamFeatures::Disabled); // check whether bind is available if (features.bindMode() != QXmppStreamFeatures::Disabled) { QXmppBindIq bind; bind.setType(QXmppIq::Set); bind.setResource(configuration().resource()); d->bindId = bind.id(); sendPacket(bind); return; } // check whether session is available if (d->sessionAvailable) { // start session if it is available QXmppSessionIq session; session.setType(QXmppIq::Set); session.setTo(configuration().domain()); d->sessionId = session.id(); sendPacket(session); } else { // otherwise we are done d->sessionStarted = true; emit connected(); } } else if(ns == ns_stream && nodeRecv.tagName() == "error") { // handle redirects QRegExp redirectRegex("([^:]+)(:[0-9]+)?"); if (redirectRegex.exactMatch(nodeRecv.firstChildElement("see-other-host").text())) { d->redirectHost = redirectRegex.cap(0); if (!redirectRegex.cap(2).isEmpty()) d->redirectPort = redirectRegex.cap(2).mid(1).toUShort(); else d->redirectPort = 5222; disconnectFromHost(); return; } if (!nodeRecv.firstChildElement("conflict").isNull()) d->xmppStreamError = QXmppStanza::Error::Conflict; else d->xmppStreamError = QXmppStanza::Error::UndefinedCondition; emit error(QXmppClient::XmppStreamError); } else if(ns == ns_tls) { if(nodeRecv.tagName() == "proceed") { debug("Starting encryption"); socket()->startClientEncryption(); return; } } else if(ns == ns_sasl) { if (!d->saslClient) { warning("SASL stanza received, but no mechanism selected"); return; } if(nodeRecv.tagName() == "success") { debug("Authenticated"); d->isAuthenticated = true; handleStart(); } else if(nodeRecv.tagName() == "challenge") { QXmppSaslChallenge challenge; challenge.parse(nodeRecv); QByteArray response; if (d->saslClient->respond(challenge.value(), response)) { sendPacket(QXmppSaslResponse(response)); } else { warning("Could not respond to SASL challenge"); disconnectFromHost(); } } else if(nodeRecv.tagName() == "failure") { QXmppSaslFailure failure; failure.parse(nodeRecv); // RFC3920 defines the error condition as "not-authorized", but // some broken servers use "bad-auth" instead. We tolerate this // by remapping the error to "not-authorized". if (failure.condition() == "not-authorized" || failure.condition() == "bad-auth") d->xmppStreamError = QXmppStanza::Error::NotAuthorized; else d->xmppStreamError = QXmppStanza::Error::UndefinedCondition; emit error(QXmppClient::XmppStreamError); warning("Authentication failure"); disconnectFromHost(); } } else if(ns == ns_client) { if(nodeRecv.tagName() == "iq") { QDomElement element = nodeRecv.firstChildElement(); QString id = nodeRecv.attribute("id"); QString type = nodeRecv.attribute("type"); if(type.isEmpty()) warning("QXmppStream: iq type can't be empty"); if(id == d->sessionId) { QXmppSessionIq session; session.parse(nodeRecv); // xmpp connection made d->sessionStarted = true; emit connected(); } else if(QXmppBindIq::isBindIq(nodeRecv) && id == d->bindId) { QXmppBindIq bind; bind.parse(nodeRecv); // bind result if (bind.type() == QXmppIq::Result) { if (!bind.jid().isEmpty()) { QRegExp jidRegex("^([^@/]+)@([^@/]+)/(.+)$"); if (jidRegex.exactMatch(bind.jid())) { configuration().setUser(jidRegex.cap(1)); configuration().setDomain(jidRegex.cap(2)); configuration().setResource(jidRegex.cap(3)); } else { warning("Bind IQ received with invalid JID: " + bind.jid()); } } if (d->sessionAvailable) { // start session if it is available QXmppSessionIq session; session.setType(QXmppIq::Set); session.setTo(configuration().domain()); d->sessionId = session.id(); sendPacket(session); } else { // otherwise we are done d->sessionStarted = true; emit connected(); } } } // extensions // XEP-0078: Non-SASL Authentication else if(id == d->nonSASLAuthId && type == "result") { // successful Non-SASL Authentication debug("Authenticated (Non-SASL)"); d->isAuthenticated = true; // xmpp connection made d->sessionStarted = true; emit connected(); } else if(QXmppNonSASLAuthIq::isNonSASLAuthIq(nodeRecv)) { if(type == "result") { bool digest = !nodeRecv.firstChildElement("query"). firstChildElement("digest").isNull(); bool plain = !nodeRecv.firstChildElement("query"). firstChildElement("password").isNull(); bool plainText = false; if(plain && digest) { if(configuration().nonSASLAuthMechanism() == QXmppConfiguration::NonSASLDigest) plainText = false; else plainText = true; } else if(plain) plainText = true; else if(digest) plainText = false; else { warning("No supported Non-SASL Authentication mechanism available"); disconnectFromHost(); return; } sendNonSASLAuth(plainText); } } // XEP-0199: XMPP Ping else if(QXmppPingIq::isPingIq(nodeRecv)) { QXmppPingIq req; req.parse(nodeRecv); QXmppIq iq(QXmppIq::Result); iq.setId(req.id()); iq.setTo(req.from()); sendPacket(iq); } else { QXmppIq iqPacket; iqPacket.parse(nodeRecv); // if we didn't understant the iq, reply with error // except for "result" and "error" iqs if (type != "result" && type != "error") { QXmppIq iq(QXmppIq::Error); iq.setId(iqPacket.id()); iq.setTo(iqPacket.from()); QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::FeatureNotImplemented); iq.setError(error); sendPacket(iq); } else { emit iqReceived(iqPacket); } } } else if(nodeRecv.tagName() == "presence") { QXmppPresence presence; presence.parse(nodeRecv); // emit presence emit presenceReceived(presence); } else if(nodeRecv.tagName() == "message") { QXmppMessage message; message.parse(nodeRecv); // emit message emit messageReceived(message); } } } /// \endcond void QXmppOutgoingClient::pingStart() { const int interval = configuration().keepAliveInterval(); // start ping timer if (interval > 0) { d->pingTimer->setInterval(interval * 1000); d->pingTimer->start(); } } void QXmppOutgoingClient::pingStop() { // stop all timers d->pingTimer->stop(); d->timeoutTimer->stop(); } void QXmppOutgoingClient::pingSend() { // send ping packet QXmppPingIq ping; ping.setTo(configuration().domain()); sendPacket(ping); // start timeout timer const int timeout = configuration().keepAliveTimeout(); if (timeout > 0) { d->timeoutTimer->setInterval(timeout * 1000); d->timeoutTimer->start(); } } void QXmppOutgoingClient::pingTimeout() { warning("Ping timeout"); disconnectFromHost(); emit error(QXmppClient::KeepAliveError); } void QXmppOutgoingClient::sendNonSASLAuth(bool plainText) { QXmppNonSASLAuthIq authQuery; authQuery.setType(QXmppIq::Set); authQuery.setUsername(configuration().user()); if (plainText) authQuery.setPassword(configuration().password()); else authQuery.setDigest(d->streamId, configuration().password()); authQuery.setResource(configuration().resource()); d->nonSASLAuthId = authQuery.id(); sendPacket(authQuery); } void QXmppOutgoingClient::sendNonSASLAuthQuery() { QXmppNonSASLAuthIq authQuery; authQuery.setType(QXmppIq::Get); authQuery.setTo(d->streamFrom); // FIXME : why are we setting the username, XEP-0078 states we should // not attempt to guess the required fields? authQuery.setUsername(configuration().user()); sendPacket(authQuery); } /// Returns the type of the last XMPP stream error that occured. QXmppStanza::Error::Condition QXmppOutgoingClient::xmppStreamError() { return d->xmppStreamError; } qxmpp-0.9.3/src/client/QXmppOutgoingClient.h000066400000000000000000000055301263006255200210320ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPOUTGOINGCLIENT_H #define QXMPPOUTGOINGCLIENT_H #include "QXmppClient.h" #include "QXmppStanza.h" #include "QXmppStream.h" class QDomElement; class QSslError; class QXmppConfiguration; class QXmppPresence; class QXmppIq; class QXmppMessage; class QXmppOutgoingClientPrivate; /// \brief The QXmppOutgoingClient class represents an outgoing XMPP stream /// to an XMPP server. /// class QXMPP_EXPORT QXmppOutgoingClient : public QXmppStream { Q_OBJECT public: QXmppOutgoingClient(QObject *parent); ~QXmppOutgoingClient(); void connectToHost(); bool isAuthenticated() const; bool isConnected() const; QSslSocket *socket() const { return QXmppStream::socket(); }; QXmppStanza::Error::Condition xmppStreamError(); QXmppConfiguration& configuration(); signals: /// This signal is emitted when an error is encountered. void error(QXmppClient::Error); /// This signal is emitted when an element is received. void elementReceived(const QDomElement &element, bool &handled); /// This signal is emitted when a presence is received. void presenceReceived(const QXmppPresence&); /// This signal is emitted when a message is received. void messageReceived(const QXmppMessage&); /// This signal is emitted when an IQ is received. void iqReceived(const QXmppIq&); /// This signal is emitted when SSL errors are encountered. void sslErrors(const QList &errors); protected: /// \cond // Overridable methods virtual void handleStart(); virtual void handleStanza(const QDomElement &element); virtual void handleStream(const QDomElement &element); /// \endcond private slots: void _q_dnsLookupFinished(); void _q_socketDisconnected(); void socketError(QAbstractSocket::SocketError); void socketSslErrors(const QList&); void pingStart(); void pingStop(); void pingSend(); void pingTimeout(); private: void sendNonSASLAuth(bool plaintext); void sendNonSASLAuthQuery(); friend class QXmppOutgoingClientPrivate; QXmppOutgoingClientPrivate * const d; }; #endif // QXMPPOUTGOINGCLIENT_H qxmpp-0.9.3/src/client/QXmppRemoteMethod.cpp000066400000000000000000000042631263006255200210310ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Ian Reinhart Geiser * * Source: * https://github.com/qxmpp-project/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 "QXmppRemoteMethod.h" #include "QXmppClient.h" #include "QXmppUtils.h" #include #include #include QXmppRemoteMethod::QXmppRemoteMethod(const QString &jid, const QString &method, const QVariantList &args, QXmppClient *client) : QObject(client), m_client(client) { m_payload.setTo( jid ); m_payload.setFrom( client->configuration().jid() ); m_payload.setMethod( method ); m_payload.setArguments( args ); } QXmppRemoteMethodResult QXmppRemoteMethod::call( ) { // FIXME : spinning an event loop is a VERY bad idea, it can cause // us to lose incoming packets QEventLoop loop(this); connect( this, SIGNAL(callDone()), &loop, SLOT(quit())); QTimer::singleShot(30000,&loop, SLOT(quit())); // Timeout incase the other end hangs... m_client->sendPacket( m_payload ); loop.exec( QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents ); return m_result; } void QXmppRemoteMethod::gotError( const QXmppRpcErrorIq &iq ) { if ( iq.id() == m_payload.id() ) { m_result.hasError = true; m_result.errorMessage = iq.error().text(); m_result.code = iq.error().type(); emit callDone(); } } void QXmppRemoteMethod::gotResult( const QXmppRpcResponseIq &iq ) { if ( iq.id() == m_payload.id() ) { m_result.hasError = false; // FIXME: we don't handle multiple responses m_result.result = iq.values().first(); emit callDone(); } } qxmpp-0.9.3/src/client/QXmppRemoteMethod.h000066400000000000000000000030231263006255200204670ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Ian Reinhart Geiser * * Source: * https://github.com/qxmpp-project/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 QXMPPREMOTEMETHOD_H #define QXMPPREMOTEMETHOD_H #include #include #include "QXmppRpcIq.h" class QXmppClient; struct QXmppRemoteMethodResult { QXmppRemoteMethodResult() : hasError(false), code(0) { } bool hasError; int code; QString errorMessage; QVariant result; }; class QXMPP_EXPORT QXmppRemoteMethod : public QObject { Q_OBJECT public: QXmppRemoteMethod(const QString &jid, const QString &method, const QVariantList &args, QXmppClient *client); QXmppRemoteMethodResult call( ); private slots: void gotError( const QXmppRpcErrorIq &iq ); void gotResult( const QXmppRpcResponseIq &iq ); signals: void callDone(); private: QXmppRpcInvokeIq m_payload; QXmppClient *m_client; QXmppRemoteMethodResult m_result; }; #endif // QXMPPREMOTEMETHOD_H qxmpp-0.9.3/src/client/QXmppRosterManager.cpp000066400000000000000000000271211263006255200212040ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppClient.h" #include "QXmppPresence.h" #include "QXmppRosterIq.h" #include "QXmppRosterManager.h" #include "QXmppUtils.h" class QXmppRosterManagerPrivate { public: QXmppRosterManagerPrivate(QXmppRosterManager *qq); // map of bareJid and its rosterEntry QMap entries; // map of resources of the jid and map of resources and presences QMap > presences; // flag to store that the roster has been populated bool isRosterReceived; // id of the initial roster request QString rosterReqId; private: QXmppRosterManager *q; }; QXmppRosterManagerPrivate::QXmppRosterManagerPrivate(QXmppRosterManager *qq) : isRosterReceived(false), q(qq) { } /// Constructs a roster manager. QXmppRosterManager::QXmppRosterManager(QXmppClient* client) { bool check; Q_UNUSED(check); d = new QXmppRosterManagerPrivate(this); check = connect(client, SIGNAL(connected()), this, SLOT(_q_connected())); Q_ASSERT(check); check = connect(client, SIGNAL(disconnected()), this, SLOT(_q_disconnected())); Q_ASSERT(check); check = connect(client, SIGNAL(presenceReceived(QXmppPresence)), this, SLOT(_q_presenceReceived(QXmppPresence))); Q_ASSERT(check); } QXmppRosterManager::~QXmppRosterManager() { delete d; } /// Accepts a subscription request. /// /// You can call this method in reply to the subscriptionRequest() signal. bool QXmppRosterManager::acceptSubscription(const QString &bareJid, const QString &reason) { QXmppPresence presence; presence.setTo(bareJid); presence.setType(QXmppPresence::Subscribed); presence.setStatusText(reason); return client()->sendPacket(presence); } /// Upon XMPP connection, request the roster. /// void QXmppRosterManager::_q_connected() { QXmppRosterIq roster; roster.setType(QXmppIq::Get); roster.setFrom(client()->configuration().jid()); d->rosterReqId = roster.id(); if (client()->isAuthenticated()) client()->sendPacket(roster); } void QXmppRosterManager::_q_disconnected() { d->entries.clear(); d->presences.clear(); d->isRosterReceived = false; } /// \cond bool QXmppRosterManager::handleStanza(const QDomElement &element) { if (element.tagName() != "iq" || !QXmppRosterIq::isRosterIq(element)) return false; // Security check: only server should send this iq // from() should be either empty or bareJid of the user const QString fromJid = element.attribute("from"); if (!fromJid.isEmpty() && QXmppUtils::jidToBareJid(fromJid) != client()->configuration().jidBare()) return false; QXmppRosterIq rosterIq; rosterIq.parse(element); bool isInitial = (d->rosterReqId == rosterIq.id()); switch(rosterIq.type()) { case QXmppIq::Set: { // send result iq QXmppIq returnIq(QXmppIq::Result); returnIq.setId(rosterIq.id()); client()->sendPacket(returnIq); // store updated entries and notify changes const QList items = rosterIq.items(); foreach (const QXmppRosterIq::Item &item, items) { const QString bareJid = item.bareJid(); if (item.subscriptionType() == QXmppRosterIq::Item::Remove) { if (d->entries.remove(bareJid)) { // notify the user that the item was removed emit itemRemoved(bareJid); } } else { const bool added = !d->entries.contains(bareJid); d->entries.insert(bareJid, item); if (added) { // notify the user that the item was added emit itemAdded(bareJid); } else { // notify the user that the item changed emit itemChanged(bareJid); } } } } break; case QXmppIq::Result: { const QList items = rosterIq.items(); foreach (const QXmppRosterIq::Item &item, items) { const QString bareJid = item.bareJid(); d->entries.insert(bareJid, item); } if (isInitial) { d->isRosterReceived = true; emit rosterReceived(); } break; } default: break; } return true; } /// \endcond void QXmppRosterManager::_q_presenceReceived(const QXmppPresence& presence) { const QString jid = presence.from(); const QString bareJid = QXmppUtils::jidToBareJid(jid); const QString resource = QXmppUtils::jidToResource(jid); if (bareJid.isEmpty()) return; switch(presence.type()) { case QXmppPresence::Available: d->presences[bareJid][resource] = presence; emit presenceChanged(bareJid, resource); break; case QXmppPresence::Unavailable: d->presences[bareJid].remove(resource); emit presenceChanged(bareJid, resource); break; case QXmppPresence::Subscribe: if (client()->configuration().autoAcceptSubscriptions()) { // accept subscription request acceptSubscription(bareJid); // ask for reciprocal subscription subscribe(bareJid); } else { emit subscriptionReceived(bareJid); } break; default: break; } } /// Refuses a subscription request. /// /// You can call this method in reply to the subscriptionRequest() signal. bool QXmppRosterManager::refuseSubscription(const QString &bareJid, const QString &reason) { QXmppPresence presence; presence.setTo(bareJid); presence.setType(QXmppPresence::Unsubscribed); presence.setStatusText(reason); return client()->sendPacket(presence); } /// Adds a new item to the roster without sending any subscription requests. /// /// As a result, the server will initiate a roster push, causing the /// itemAdded() or itemChanged() signal to be emitted. /// /// \param bareJid /// \param name Optional name for the item. /// \param groups Optional groups for the item. bool QXmppRosterManager::addItem(const QString &bareJid, const QString &name, const QSet &groups) { QXmppRosterIq::Item item; item.setBareJid(bareJid); item.setName(name); item.setGroups(groups); item.setSubscriptionType(QXmppRosterIq::Item::NotSet); QXmppRosterIq iq; iq.setType(QXmppIq::Set); iq.addItem(item); return client()->sendPacket(iq); } /// Removes a roster item and cancels subscriptions to and from the contact. /// /// As a result, the server will initiate a roster push, causing the /// itemRemoved() signal to be emitted. /// /// \param bareJid bool QXmppRosterManager::removeItem(const QString &bareJid) { QXmppRosterIq::Item item; item.setBareJid(bareJid); item.setSubscriptionType(QXmppRosterIq::Item::Remove); QXmppRosterIq iq; iq.setType(QXmppIq::Set); iq.addItem(item); return client()->sendPacket(iq); } /// Renames a roster item. /// /// As a result, the server will initiate a roster push, causing the /// itemChanged() signal to be emitted. /// /// \param bareJid /// \param name bool QXmppRosterManager::renameItem(const QString &bareJid, const QString &name) { if (!d->entries.contains(bareJid)) return false; QXmppRosterIq::Item item = d->entries.value(bareJid); item.setName(name); QXmppRosterIq iq; iq.setType(QXmppIq::Set); iq.addItem(item); return client()->sendPacket(iq); } /// Requests a subscription to the given contact. /// /// As a result, the server will initiate a roster push, causing the /// itemAdded() or itemChanged() signal to be emitted. bool QXmppRosterManager::subscribe(const QString &bareJid, const QString &reason) { QXmppPresence packet; packet.setTo(QXmppUtils::jidToBareJid(bareJid)); packet.setType(QXmppPresence::Subscribe); packet.setStatusText(reason); return client()->sendPacket(packet); } /// Removes a subscription to the given contact. /// /// As a result, the server will initiate a roster push, causing the /// itemChanged() signal to be emitted. bool QXmppRosterManager::unsubscribe(const QString &bareJid, const QString &reason) { QXmppPresence packet; packet.setTo(QXmppUtils::jidToBareJid(bareJid)); packet.setType(QXmppPresence::Unsubscribe); packet.setStatusText(reason); return client()->sendPacket(packet); } /// Function to get all the bareJids present in the roster. /// /// \return QStringList list of all the bareJids /// QStringList QXmppRosterManager::getRosterBareJids() const { return d->entries.keys(); } /// Returns the roster entry of the given bareJid. If the bareJid is not in the /// database and empty QXmppRosterIq::Item will be returned. /// /// \param bareJid as a QString /// QXmppRosterIq::Item QXmppRosterManager::getRosterEntry( const QString& bareJid) const { // will return blank entry if bareJid does'nt exist if(d->entries.contains(bareJid)) return d->entries.value(bareJid); else return QXmppRosterIq::Item(); } /// Get all the associated resources with the given bareJid. /// /// \param bareJid as a QString /// \return list of associated resources as a QStringList /// QStringList QXmppRosterManager::getResources(const QString& bareJid) const { if(d->presences.contains(bareJid)) return d->presences[bareJid].keys(); else return QStringList(); } /// Get all the presences of all the resources of the given bareJid. A bareJid /// can have multiple resources and each resource will have a presence /// associated with it. /// /// \param bareJid as a QString /// \return Map of resource and its respective presence QMap /// QMap QXmppRosterManager::getAllPresencesForBareJid( const QString& bareJid) const { if(d->presences.contains(bareJid)) return d->presences[bareJid]; else return QMap(); } /// Get the presence of the given resource of the given bareJid. /// /// \param bareJid as a QString /// \param resource as a QString /// \return QXmppPresence /// QXmppPresence QXmppRosterManager::getPresence(const QString& bareJid, const QString& resource) const { if(d->presences.contains(bareJid) && d->presences[bareJid].contains(resource)) return d->presences[bareJid][resource]; else { QXmppPresence presence; presence.setType(QXmppPresence::Unavailable); return presence; } } /// Function to check whether the roster has been received or not. /// /// \return true if roster received else false bool QXmppRosterManager::isRosterReceived() const { return d->isRosterReceived; } qxmpp-0.9.3/src/client/QXmppRosterManager.h000066400000000000000000000117131263006255200206510ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPROSTERMANAGER_H #define QXMPPROSTERMANAGER_H #include #include #include #include "QXmppClientExtension.h" #include "QXmppPresence.h" #include "QXmppRosterIq.h" class QXmppRosterManagerPrivate; /// \brief The QXmppRosterManager class provides access to a connected client's roster. /// /// \note It's object should not be created using it's constructor. Instead /// QXmppClient::rosterManager() should be used to get the reference of instantiated /// object this class. /// /// It stores all the Roster and Presence details of all the roster entries (that /// is all the bareJids) in the client's friend's list. It provides the /// functionality to get all the bareJids in the client's roster and Roster and /// Presence details of the same. /// /// After the successful xmpp connection that after the signal QXmppClient::connected() /// is emitted QXmpp requests for getting the roster. Once QXmpp receives the roster /// the signal QXmppRosterManager::rosterReceived() is emitted and after that user can /// use the functions of this class to get roster entries. /// /// Function QXmppRosterManager::isRosterReceived() tells whether the roster has been /// received or not. /// /// The itemAdded(), itemChanged() and itemRemoved() signals are emitted whenever roster /// entries are added, changed or removed. /// /// The presenceChanged() signal is emitted whenever the presence for a roster item changes. /// /// \ingroup Managers class QXMPP_EXPORT QXmppRosterManager : public QXmppClientExtension { Q_OBJECT public: QXmppRosterManager(QXmppClient* stream); ~QXmppRosterManager(); bool isRosterReceived() const; QStringList getRosterBareJids() const; QXmppRosterIq::Item getRosterEntry(const QString& bareJid) const; QStringList getResources(const QString& bareJid) const; QMap getAllPresencesForBareJid( const QString& bareJid) const; QXmppPresence getPresence(const QString& bareJid, const QString& resource) const; /// \cond bool handleStanza(const QDomElement &element); /// \endcond public slots: bool acceptSubscription(const QString &bareJid, const QString &reason = QString()); bool refuseSubscription(const QString &bareJid, const QString &reason = QString()); bool addItem(const QString &bareJid, const QString &name = QString(), const QSet &groups = QSet()); bool removeItem(const QString &bareJid); bool renameItem(const QString &bareJid, const QString &name); bool subscribe(const QString &bareJid, const QString &reason = QString()); bool unsubscribe(const QString &bareJid, const QString &reason = QString()); signals: /// This signal is emitted when the Roster IQ is received after a successful /// connection. That is the roster entries are empty before this signal is emitted. /// One should use getRosterBareJids() and getRosterEntry() only after /// this signal has been emitted. void rosterReceived(); /// This signal is emitted when the presence of a particular bareJid and resource changes. void presenceChanged(const QString& bareJid, const QString& resource); /// This signal is emitted when a contact asks to subscribe to your presence. /// /// You can either accept the request by calling acceptSubscription() or refuse it /// by calling refuseSubscription(). /// /// \note If you set QXmppConfiguration::autoAcceptSubscriptions() to true, this /// signal will not be emitted. void subscriptionReceived(const QString& bareJid); /// This signal is emitted when the roster entry of a particular bareJid is /// added as a result of roster push. void itemAdded(const QString& bareJid); /// This signal is emitted when the roster entry of a particular bareJid /// changes as a result of roster push. void itemChanged(const QString& bareJid); /// This signal is emitted when the roster entry of a particular bareJid is /// removed as a result of roster push. void itemRemoved(const QString& bareJid); private slots: void _q_connected(); void _q_disconnected(); void _q_presenceReceived(const QXmppPresence&); private: QXmppRosterManagerPrivate *d; }; #endif // QXMPPROSTER_H qxmpp-0.9.3/src/client/QXmppRpcManager.cpp000066400000000000000000000130521263006255200204500ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppClient.h" #include "QXmppConstants.h" #include "QXmppInvokable.h" #include "QXmppRemoteMethod.h" #include "QXmppRpcIq.h" #include "QXmppRpcManager.h" /// Constructs a QXmppRpcManager. QXmppRpcManager::QXmppRpcManager() { } /// Adds a local interface which can be queried using RPC. /// /// \param interface void QXmppRpcManager::addInvokableInterface( QXmppInvokable *interface ) { m_interfaces[ interface->metaObject()->className() ] = interface; } /// Invokes a remote interface using RPC. /// /// \param iq void QXmppRpcManager::invokeInterfaceMethod( const QXmppRpcInvokeIq &iq ) { QXmppStanza::Error error; const QStringList methodBits = iq.method().split('.'); if (methodBits.size() != 2) return; const QString interface = methodBits.first(); const QString method = methodBits.last(); QXmppInvokable *iface = m_interfaces.value(interface); if (iface) { if ( iface->isAuthorized( iq.from() ) ) { if ( iface->interfaces().contains(method) ) { QVariant result = iface->dispatch(method.toLatin1(), iq.arguments() ); QXmppRpcResponseIq resultIq; resultIq.setId(iq.id()); resultIq.setTo(iq.from()); resultIq.setValues(QVariantList() << result); client()->sendPacket( resultIq ); return; } else { error.setType(QXmppStanza::Error::Cancel); error.setCondition(QXmppStanza::Error::ItemNotFound); } } else { error.setType(QXmppStanza::Error::Auth); error.setCondition(QXmppStanza::Error::Forbidden); } } else { error.setType(QXmppStanza::Error::Cancel); error.setCondition(QXmppStanza::Error::ItemNotFound); } QXmppRpcErrorIq errorIq; errorIq.setId(iq.id()); errorIq.setTo(iq.from()); errorIq.setQuery(iq); errorIq.setError(error); client()->sendPacket(errorIq); } /// Calls a remote method using RPC with the specified arguments. /// /// \note This method blocks until the response is received, and it may /// cause XMPP stanzas to be lost! QXmppRemoteMethodResult QXmppRpcManager::callRemoteMethod( const QString &jid, const QString &interface, const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8, const QVariant &arg9, const QVariant &arg10 ) { QVariantList args; if( arg1.isValid() ) args << arg1; if( arg2.isValid() ) args << arg2; if( arg3.isValid() ) args << arg3; if( arg4.isValid() ) args << arg4; if( arg5.isValid() ) args << arg5; if( arg6.isValid() ) args << arg6; if( arg7.isValid() ) args << arg7; if( arg8.isValid() ) args << arg8; if( arg9.isValid() ) args << arg9; if( arg10.isValid() ) args << arg10; QXmppRemoteMethod method( jid, interface, args, client() ); connect(this, SIGNAL(rpcCallResponse(QXmppRpcResponseIq)), &method, SLOT(gotResult(QXmppRpcResponseIq))); connect(this, SIGNAL(rpcCallError(QXmppRpcErrorIq)), &method, SLOT(gotError(QXmppRpcErrorIq))); return method.call(); } /// \cond QStringList QXmppRpcManager::discoveryFeatures() const { // XEP-0009: Jabber-RPC return QStringList() << ns_rpc; } QList QXmppRpcManager::discoveryIdentities() const { QXmppDiscoveryIq::Identity identity; identity.setCategory("automation"); identity.setType("rpc"); return QList() << identity; } bool QXmppRpcManager::handleStanza(const QDomElement &element) { // XEP-0009: Jabber-RPC if (QXmppRpcInvokeIq::isRpcInvokeIq(element)) { QXmppRpcInvokeIq rpcIqPacket; rpcIqPacket.parse(element); invokeInterfaceMethod(rpcIqPacket); return true; } else if(QXmppRpcResponseIq::isRpcResponseIq(element)) { QXmppRpcResponseIq rpcResponseIq; rpcResponseIq.parse(element); emit rpcCallResponse(rpcResponseIq); return true; } else if(QXmppRpcErrorIq::isRpcErrorIq(element)) { QXmppRpcErrorIq rpcErrorIq; rpcErrorIq.parse(element); emit rpcCallError(rpcErrorIq); return true; } return false; } /// \endcond qxmpp-0.9.3/src/client/QXmppRpcManager.h000066400000000000000000000057751263006255200201320ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPRPCMANAGER_H #define QXMPPRPCMANAGER_H #include #include #include "QXmppClientExtension.h" #include "QXmppInvokable.h" #include "QXmppRemoteMethod.h" class QXmppRpcErrorIq; class QXmppRpcInvokeIq; class QXmppRpcResponseIq; /// \brief The QXmppRpcManager class make it possible to invoke remote methods /// and to expose local interfaces for remote procedure calls, as specified by /// XEP-0009: Jabber-RPC. /// /// To make use of this manager, you need to instantiate it and load it into /// the QXmppClient instance as follows: /// /// \code /// QXmppRpcManager *manager = new QXmppRpcManager; /// client->addExtension(manager); /// \endcode /// /// \note THIS API IS NOT FINALIZED YET /// /// \ingroup Managers class QXMPP_EXPORT QXmppRpcManager : public QXmppClientExtension { Q_OBJECT public: QXmppRpcManager(); void addInvokableInterface( QXmppInvokable *interface ); QXmppRemoteMethodResult callRemoteMethod( const QString &jid, const QString &interface, const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant(), const QVariant &arg9 = QVariant(), const QVariant &arg10 = QVariant() ); /// \cond QStringList discoveryFeatures() const; virtual QList discoveryIdentities() const; bool handleStanza(const QDomElement &element); /// \endcond signals: /// \cond void rpcCallResponse(const QXmppRpcResponseIq& result); void rpcCallError(const QXmppRpcErrorIq &err); /// \endcond private: void invokeInterfaceMethod(const QXmppRpcInvokeIq &iq); QMap m_interfaces; }; #endif qxmpp-0.9.3/src/client/QXmppTransferManager.cpp000066400000000000000000001370011263006255200215110ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppByteStreamIq.h" #include "QXmppClient.h" #include "QXmppConstants.h" #include "QXmppIbbIq.h" #include "QXmppSocks.h" #include "QXmppStreamInitiationIq_p.h" #include "QXmppStun.h" #include "QXmppTransferManager.h" #include "QXmppTransferManager_p.h" #include "QXmppUtils.h" // time to try to connect to a SOCKS host (7 seconds) const int socksTimeout = 7000; static QString streamHash(const QString &sid, const QString &initiatorJid, const QString &targetJid) { QCryptographicHash hash(QCryptographicHash::Sha1); QString str = sid + initiatorJid + targetJid; hash.addData(str.toLatin1()); return hash.result().toHex(); } class QXmppTransferFileInfoPrivate : public QSharedData { public: QXmppTransferFileInfoPrivate(); QDateTime date; QByteArray hash; QString name; QString description; qint64 size; }; QXmppTransferFileInfoPrivate::QXmppTransferFileInfoPrivate() : size(0) { } QXmppTransferFileInfo::QXmppTransferFileInfo() : d(new QXmppTransferFileInfoPrivate) { } QXmppTransferFileInfo::QXmppTransferFileInfo(const QXmppTransferFileInfo &other) : d(other.d) { } QXmppTransferFileInfo::~QXmppTransferFileInfo() { } QDateTime QXmppTransferFileInfo::date() const { return d->date; } void QXmppTransferFileInfo::setDate(const QDateTime &date) { d->date = date; } QByteArray QXmppTransferFileInfo::hash() const { return d->hash; } void QXmppTransferFileInfo::setHash(const QByteArray &hash) { d->hash = hash; } QString QXmppTransferFileInfo::name() const { return d->name; } void QXmppTransferFileInfo::setName(const QString &name) { d->name = name; } QString QXmppTransferFileInfo::description() const { return d->description; } void QXmppTransferFileInfo::setDescription(const QString &description) { d->description = description; } qint64 QXmppTransferFileInfo::size() const { return d->size; } void QXmppTransferFileInfo::setSize(qint64 size) { d->size = size; } bool QXmppTransferFileInfo::isNull() const { return d->date.isNull() && d->description.isEmpty() && d->hash.isEmpty() && d->name.isEmpty() && d->size == 0; } QXmppTransferFileInfo& QXmppTransferFileInfo::operator=(const QXmppTransferFileInfo &other) { d = other.d; return *this; } bool QXmppTransferFileInfo::operator==(const QXmppTransferFileInfo &other) const { return other.d->size == d->size && other.d->hash == d->hash && other.d->name == d->name; } void QXmppTransferFileInfo::parse(const QDomElement &element) { d->date = QXmppUtils::datetimeFromString(element.attribute("date")); d->hash = QByteArray::fromHex(element.attribute("hash").toLatin1()); d->name = element.attribute("name"); d->size = element.attribute("size").toLongLong(); d->description = element.firstChildElement("desc").text(); } void QXmppTransferFileInfo::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement("file"); writer->writeAttribute("xmlns", ns_stream_initiation_file_transfer); if (d->date.isValid()) writer->writeAttribute("date", QXmppUtils::datetimeToString(d->date)); if (!d->hash.isEmpty()) writer->writeAttribute("hash", d->hash.toHex()); if (!d->name.isEmpty()) writer->writeAttribute("name", d->name); if (d->size > 0) writer->writeAttribute("size", QString::number(d->size)); if (!d->description.isEmpty()) writer->writeTextElement("desc", d->description); writer->writeEndElement(); } class QXmppTransferJobPrivate { public: QXmppTransferJobPrivate(); int blockSize; QXmppClient *client; QXmppTransferJob::Direction direction; qint64 done; QXmppTransferJob::Error error; QCryptographicHash hash; QIODevice *iodevice; QString offerId; QString jid; QUrl localFileUrl; QString sid; QXmppTransferJob::Method method; QString mimeType; QString requestId; QXmppTransferJob::State state; QTime transferStart; bool deviceIsOwn; // file meta-data QXmppTransferFileInfo fileInfo; // for in-band bytestreams int ibbSequence; // for socks5 bytestreams QTcpSocket *socksSocket; QXmppByteStreamIq::StreamHost socksProxy; }; QXmppTransferJobPrivate::QXmppTransferJobPrivate() : blockSize(16384), client(0), done(0), error(QXmppTransferJob::NoError), hash(QCryptographicHash::Md5), iodevice(0), method(QXmppTransferJob::NoMethod), state(QXmppTransferJob::OfferState), deviceIsOwn(false), ibbSequence(0), socksSocket(0) { } QXmppTransferJob::QXmppTransferJob(const QString &jid, QXmppTransferJob::Direction direction, QXmppClient *client, QObject *parent) : QXmppLoggable(parent), d(new QXmppTransferJobPrivate) { d->client = client; d->direction = direction; d->jid = jid; } QXmppTransferJob::~QXmppTransferJob() { delete d; } /// Call this method if you wish to abort on ongoing transfer job. /// void QXmppTransferJob::abort() { terminate(AbortError); } /// Call this method if you wish to accept an incoming transfer job. /// void QXmppTransferJob::accept(const QString &filePath) { if (d->direction == IncomingDirection && d->state == OfferState && !d->iodevice) { QFile *file = new QFile(filePath, this); if (!file->open(QIODevice::WriteOnly)) { warning(QString("Could not write to %1").arg(filePath)); abort(); return; } d->iodevice = file; setLocalFileUrl(QUrl::fromLocalFile(filePath)); setState(QXmppTransferJob::StartState); } } /// Call this method if you wish to accept an incoming transfer job. /// void QXmppTransferJob::accept(QIODevice *iodevice) { if (d->direction == IncomingDirection && d->state == OfferState && !d->iodevice) { d->iodevice = iodevice; setState(QXmppTransferJob::StartState); } } /// Returns the job's transfer direction. /// QXmppTransferJob::Direction QXmppTransferJob::direction() const { return d->direction; } /// Returns the last error that was encountered. /// QXmppTransferJob::Error QXmppTransferJob::error() const { return d->error; } /// Returns the remote party's JID. /// QString QXmppTransferJob::jid() const { return d->jid; } /// Returns the local file URL. /// QUrl QXmppTransferJob::localFileUrl() const { return d->localFileUrl; } /// Sets the local file URL. /// /// \note You do not need to call this method if you called accept() /// with a file path. void QXmppTransferJob::setLocalFileUrl(const QUrl &localFileUrl) { if (localFileUrl != d->localFileUrl) { d->localFileUrl = localFileUrl; emit localFileUrlChanged(localFileUrl); } } /// Returns meta-data about the file being transferred. /// QXmppTransferFileInfo QXmppTransferJob::fileInfo() const { return d->fileInfo; } /// \cond QDateTime QXmppTransferJob::fileDate() const { return d->fileInfo.date(); } QByteArray QXmppTransferJob::fileHash() const { return d->fileInfo.hash(); } QString QXmppTransferJob::fileName() const { return d->fileInfo.name(); } qint64 QXmppTransferJob::fileSize() const { return d->fileInfo.size(); } /// \endcond /// Returns the job's transfer method. /// QXmppTransferJob::Method QXmppTransferJob::method() const { return d->method; } /// Returns the job's session identifier. /// QString QXmppTransferJob::sid() const { return d->sid; } /// Returns the job's transfer speed in bytes per second. /// /// If the transfer has not started yet or is already finished, returns 0. /// qint64 QXmppTransferJob::speed() const { qint64 elapsed = d->transferStart.elapsed(); if (d->state != QXmppTransferJob::TransferState || !elapsed) return 0; return (d->done * 1000.0) / elapsed; } /// Returns the job's state. /// QXmppTransferJob::State QXmppTransferJob::state() const { return d->state; } void QXmppTransferJob::setState(QXmppTransferJob::State state) { if (d->state != state) { d->state = state; if (d->state == QXmppTransferJob::TransferState) d->transferStart.start(); emit stateChanged(d->state); } } void QXmppTransferJob::_q_terminated() { emit stateChanged(d->state); if (d->error != NoError) emit error(d->error); emit finished(); } void QXmppTransferJob::terminate(QXmppTransferJob::Error cause) { if (d->state == FinishedState) return; // change state d->error = cause; d->state = FinishedState; // close IO device if (d->iodevice && d->deviceIsOwn) d->iodevice->close(); // close socket if (d->socksSocket) { d->socksSocket->flush(); d->socksSocket->close(); } // emit signals later QTimer::singleShot(0, this, SLOT(_q_terminated())); } /// \cond QXmppTransferIncomingJob::QXmppTransferIncomingJob(const QString& jid, QXmppClient* client, QObject* parent) : QXmppTransferJob(jid, IncomingDirection, client, parent) , m_candidateClient(0) , m_candidateTimer(0) { } void QXmppTransferIncomingJob::checkData() { if ((d->fileInfo.size() && d->done != d->fileInfo.size()) || (!d->fileInfo.hash().isEmpty() && d->hash.result() != d->fileInfo.hash())) terminate(QXmppTransferJob::FileCorruptError); else terminate(QXmppTransferJob::NoError); } void QXmppTransferIncomingJob::connectToNextHost() { bool check; Q_UNUSED(check); if (m_streamCandidates.isEmpty()) { // could not connect to any stream host QXmppByteStreamIq response; response.setId(m_streamOfferId); response.setTo(m_streamOfferFrom); QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::ItemNotFound); error.setCode(404); response.setType(QXmppIq::Error); response.setError(error); d->client->sendPacket(response); terminate(QXmppTransferJob::ProtocolError); return; } // try next host m_candidateHost = m_streamCandidates.takeFirst(); info(QString("Connecting to streamhost: %1 (%2 %3)").arg( m_candidateHost.jid(), m_candidateHost.host(), QString::number(m_candidateHost.port()))); const QString hostName = streamHash(d->sid, d->jid, d->client->configuration().jid()); // try to connect to stream host m_candidateClient = new QXmppSocksClient(m_candidateHost.host(), m_candidateHost.port(), this); m_candidateTimer = new QTimer(this); check = connect(m_candidateClient, SIGNAL(disconnected()), this, SLOT(_q_candidateDisconnected())); Q_ASSERT(check); check = connect(m_candidateClient, SIGNAL(ready()), this, SLOT(_q_candidateReady())); Q_ASSERT(check); check = connect(m_candidateTimer, SIGNAL(timeout()), this, SLOT(_q_candidateDisconnected())); Q_ASSERT(check); m_candidateTimer->setSingleShot(true); m_candidateTimer->start(socksTimeout); m_candidateClient->connectToHost(hostName, 0); } void QXmppTransferIncomingJob::connectToHosts(const QXmppByteStreamIq &iq) { bool check; Q_UNUSED(check); m_streamCandidates = iq.streamHosts(); m_streamOfferId = iq.id(); m_streamOfferFrom = iq.from(); connectToNextHost(); } bool QXmppTransferIncomingJob::writeData(const QByteArray &data) { const qint64 written = d->iodevice->write(data); if (written < 0) return false; d->done += written; if (!d->fileInfo.hash().isEmpty()) d->hash.addData(data); progress(d->done, d->fileInfo.size()); return true; } void QXmppTransferIncomingJob::_q_candidateReady() { bool check; Q_UNUSED(check); if (!m_candidateClient) return; info(QString("Connected to streamhost: %1 (%2 %3)").arg( m_candidateHost.jid(), m_candidateHost.host(), QString::number(m_candidateHost.port()))); setState(QXmppTransferJob::TransferState); d->socksSocket = m_candidateClient; m_candidateClient = 0; m_candidateTimer->deleteLater(); m_candidateTimer = 0; check = connect(d->socksSocket, SIGNAL(readyRead()), this, SLOT(_q_receiveData())); Q_ASSERT(check); check = connect(d->socksSocket, SIGNAL(disconnected()), this, SLOT(_q_disconnected())); Q_ASSERT(check); QXmppByteStreamIq ackIq; ackIq.setId(m_streamOfferId); ackIq.setTo(m_streamOfferFrom); ackIq.setType(QXmppIq::Result); ackIq.setSid(d->sid); ackIq.setStreamHostUsed(m_candidateHost.jid()); d->client->sendPacket(ackIq); } void QXmppTransferIncomingJob::_q_candidateDisconnected() { if (!m_candidateClient) return; warning(QString("Failed to connect to streamhost: %1 (%2 %3)").arg( m_candidateHost.jid(), m_candidateHost.host(), QString::number(m_candidateHost.port()))); m_candidateClient->deleteLater(); m_candidateClient = 0; m_candidateTimer->deleteLater(); m_candidateTimer = 0; // try next host connectToNextHost(); } void QXmppTransferIncomingJob::_q_disconnected() { if (d->state == QXmppTransferJob::FinishedState) return; checkData(); } void QXmppTransferIncomingJob::_q_receiveData() { if (d->state != QXmppTransferJob::TransferState) return; // receive data block if (d->direction == QXmppTransferJob::IncomingDirection) { writeData(d->socksSocket->readAll()); // if we have received all the data, stop here if (fileSize() && d->done >= fileSize()) checkData(); } } QXmppTransferOutgoingJob::QXmppTransferOutgoingJob(const QString& jid, QXmppClient* client, QObject* parent) : QXmppTransferJob(jid, OutgoingDirection, client, parent) { } void QXmppTransferOutgoingJob::connectToProxy() { bool check; Q_UNUSED(check); info(QString("Connecting to proxy: %1 (%2 %3)").arg( d->socksProxy.jid(), d->socksProxy.host(), QString::number(d->socksProxy.port()))); const QString hostName = streamHash(d->sid, d->client->configuration().jid(), d->jid); QXmppSocksClient *socksClient = new QXmppSocksClient(d->socksProxy.host(), d->socksProxy.port(), this); check = connect(socksClient, SIGNAL(disconnected()), this, SLOT(_q_disconnected())); Q_ASSERT(check); check = connect(socksClient, SIGNAL(ready()), this, SLOT(_q_proxyReady())); Q_ASSERT(check); d->socksSocket = socksClient; socksClient->connectToHost(hostName, 0); } void QXmppTransferOutgoingJob::startSending() { bool check; Q_UNUSED(check); setState(QXmppTransferJob::TransferState); check = connect(d->socksSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(_q_sendData())); Q_ASSERT(check); check = connect(d->iodevice, SIGNAL(readyRead()), this, SLOT(_q_sendData())); Q_ASSERT(check); _q_sendData(); } void QXmppTransferOutgoingJob::_q_disconnected() { if (d->state == QXmppTransferJob::FinishedState) return; if (fileSize() && d->done != fileSize()) terminate(QXmppTransferJob::ProtocolError); else terminate(QXmppTransferJob::NoError); } void QXmppTransferOutgoingJob::_q_proxyReady() { // activate stream QXmppByteStreamIq streamIq; streamIq.setType(QXmppIq::Set); streamIq.setFrom(d->client->configuration().jid()); streamIq.setTo(d->socksProxy.jid()); streamIq.setSid(d->sid); streamIq.setActivate(d->jid); d->requestId = streamIq.id(); d->client->sendPacket(streamIq); } void QXmppTransferOutgoingJob::_q_sendData() { if (d->state != QXmppTransferJob::TransferState) return; // don't saturate the outgoing socket if (d->socksSocket->bytesToWrite() > 2 * d->blockSize) return; // check whether we have written the whole file if (d->fileInfo.size() && d->done >= d->fileInfo.size()) { if (!d->socksSocket->bytesToWrite()) terminate(QXmppTransferJob::NoError); return; } char *buffer = new char[d->blockSize]; qint64 length = d->iodevice->read(buffer, d->blockSize); if (length < 0) { delete [] buffer; terminate(QXmppTransferJob::FileAccessError); return; } if (length >= 0) { d->socksSocket->write(buffer, length); delete [] buffer; d->done += length; emit progress(d->done, fileSize()); } } /// \endcond class QXmppTransferManagerPrivate { public: QXmppTransferManagerPrivate(QXmppTransferManager *qq); QXmppTransferIncomingJob *getIncomingJobByRequestId(const QString &jid, const QString &id); QXmppTransferIncomingJob *getIncomingJobBySid(const QString &jid, const QString &sid); QXmppTransferOutgoingJob *getOutgoingJobByRequestId(const QString &jid, const QString &id); int ibbBlockSize; QList jobs; QString proxy; bool proxyOnly; QXmppSocksServer *socksServer; QXmppTransferJob::Methods supportedMethods; private: QXmppTransferJob *getJobByRequestId(QXmppTransferJob::Direction direction, const QString &jid, const QString &id); QXmppTransferManager *q; }; QXmppTransferManagerPrivate::QXmppTransferManagerPrivate(QXmppTransferManager *qq) : ibbBlockSize(4096) , proxyOnly(false) , socksServer(0) , supportedMethods(QXmppTransferJob::AnyMethod) , q(qq) { } QXmppTransferJob* QXmppTransferManagerPrivate::getJobByRequestId(QXmppTransferJob::Direction direction, const QString &jid, const QString &id) { foreach (QXmppTransferJob *job, jobs) if (job->d->direction == direction && job->d->jid == jid && job->d->requestId == id) return job; return 0; } QXmppTransferIncomingJob *QXmppTransferManagerPrivate::getIncomingJobByRequestId(const QString &jid, const QString &id) { return static_cast(getJobByRequestId(QXmppTransferJob::IncomingDirection, jid, id)); } QXmppTransferIncomingJob* QXmppTransferManagerPrivate::getIncomingJobBySid(const QString &jid, const QString &sid) { foreach (QXmppTransferJob *job, jobs) if (job->d->direction == QXmppTransferJob::IncomingDirection && job->d->jid == jid && job->d->sid == sid) return static_cast(job); return 0; } QXmppTransferOutgoingJob *QXmppTransferManagerPrivate::getOutgoingJobByRequestId(const QString &jid, const QString &id) { return static_cast(getJobByRequestId(QXmppTransferJob::OutgoingDirection, jid, id)); } /// Constructs a QXmppTransferManager to handle incoming and outgoing /// file transfers. QXmppTransferManager::QXmppTransferManager() { bool check; Q_UNUSED(check); d = new QXmppTransferManagerPrivate(this); // start SOCKS server d->socksServer = new QXmppSocksServer(this); check = connect(d->socksServer, SIGNAL(newConnection(QTcpSocket*,QString,quint16)), this, SLOT(_q_socksServerConnected(QTcpSocket*,QString,quint16))); Q_ASSERT(check); if (!d->socksServer->listen()) { qWarning("QXmppSocksServer could not start listening"); } } QXmppTransferManager::~QXmppTransferManager() { delete d; } void QXmppTransferManager::byteStreamIqReceived(const QXmppByteStreamIq &iq) { // handle IQ from proxy foreach (QXmppTransferJob *job, d->jobs) { if (job->d->socksProxy.jid() == iq.from() && job->d->requestId == iq.id()) { if (iq.type() == QXmppIq::Result && iq.streamHosts().size() > 0) { job->d->socksProxy = iq.streamHosts().first(); socksServerSendOffer(job); return; } } } if (iq.type() == QXmppIq::Result) byteStreamResultReceived(iq); else if (iq.type() == QXmppIq::Set) byteStreamSetReceived(iq); } /// Handle a response to a bystream set, i.e. after we informed the remote party /// that we connected to a stream host. void QXmppTransferManager::byteStreamResponseReceived(const QXmppIq &iq) { QXmppTransferJob *job = d->getIncomingJobByRequestId(iq.from(), iq.id()); if (!job || job->method() != QXmppTransferJob::SocksMethod || job->state() != QXmppTransferJob::StartState) return; if (iq.type() == QXmppIq::Error) job->terminate(QXmppTransferJob::ProtocolError); } /// Handle a bytestream result, i.e. after the remote party has connected to /// a stream host. void QXmppTransferManager::byteStreamResultReceived(const QXmppByteStreamIq &iq) { bool check; Q_UNUSED(check); QXmppTransferOutgoingJob *job = d->getOutgoingJobByRequestId(iq.from(), iq.id()); if (!job || job->method() != QXmppTransferJob::SocksMethod || job->state() != QXmppTransferJob::StartState) return; // check the stream host if (iq.streamHostUsed() == job->d->socksProxy.jid()) { job->connectToProxy(); return; } // direction connection, start sending data if (!job->d->socksSocket) { warning("Client says they connected to our SOCKS server, but they did not"); job->terminate(QXmppTransferJob::ProtocolError); return; } check = connect(job->d->socksSocket, SIGNAL(disconnected()), job, SLOT(_q_disconnected())); Q_ASSERT(check); job->startSending(); } /// Handle a bytestream set, i.e. an invitation from the remote party to connect /// to a stream host. void QXmppTransferManager::byteStreamSetReceived(const QXmppByteStreamIq &iq) { bool check; Q_UNUSED(check); QXmppIq response; response.setId(iq.id()); response.setTo(iq.from()); QXmppTransferIncomingJob *job = d->getIncomingJobBySid(iq.from(), iq.sid()); if (!job || job->method() != QXmppTransferJob::SocksMethod || job->state() != QXmppTransferJob::StartState) { // the stream is unknown QXmppStanza::Error error(QXmppStanza::Error::Auth, QXmppStanza::Error::NotAcceptable); error.setCode(406); response.setType(QXmppIq::Error); response.setError(error); client()->sendPacket(response); return; } job->connectToHosts(iq); } /// \cond QStringList QXmppTransferManager::discoveryFeatures() const { return QStringList() << ns_ibb // XEP-0047: In-Band Bytestreams << ns_bytestreams // XEP-0065: SOCKS5 Bytestreams << ns_stream_initiation // XEP-0095: Stream Initiation << ns_stream_initiation_file_transfer; // XEP-0096: SI File Transfer } bool QXmppTransferManager::handleStanza(const QDomElement &element) { if (element.tagName() != "iq") return false; // XEP-0047 In-Band Bytestreams if(QXmppIbbCloseIq::isIbbCloseIq(element)) { QXmppIbbCloseIq ibbCloseIq; ibbCloseIq.parse(element); ibbCloseIqReceived(ibbCloseIq); return true; } else if(QXmppIbbDataIq::isIbbDataIq(element)) { QXmppIbbDataIq ibbDataIq; ibbDataIq.parse(element); ibbDataIqReceived(ibbDataIq); return true; } else if(QXmppIbbOpenIq::isIbbOpenIq(element)) { QXmppIbbOpenIq ibbOpenIq; ibbOpenIq.parse(element); ibbOpenIqReceived(ibbOpenIq); return true; } // XEP-0065: SOCKS5 Bytestreams else if(QXmppByteStreamIq::isByteStreamIq(element)) { QXmppByteStreamIq byteStreamIq; byteStreamIq.parse(element); byteStreamIqReceived(byteStreamIq); return true; } // XEP-0095: Stream Initiation else if(QXmppStreamInitiationIq::isStreamInitiationIq(element)) { QXmppStreamInitiationIq siIq; siIq.parse(element); streamInitiationIqReceived(siIq); return true; } return false; } void QXmppTransferManager::setClient(QXmppClient *client) { bool check; Q_UNUSED(check); QXmppClientExtension::setClient(client); // XEP-0047: In-Band Bytestreams check = connect(client, SIGNAL(iqReceived(QXmppIq)), this, SLOT(_q_iqReceived(QXmppIq))); Q_ASSERT(check); } /// \endcond void QXmppTransferManager::ibbCloseIqReceived(const QXmppIbbCloseIq &iq) { QXmppIq response; response.setTo(iq.from()); response.setId(iq.id()); QXmppTransferIncomingJob *job = d->getIncomingJobBySid(iq.from(), iq.sid()); if (!job || job->method() != QXmppTransferJob::InBandMethod) { // the job is unknown, cancel it QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::ItemNotFound); response.setType(QXmppIq::Error); response.setError(error); client()->sendPacket(response); return; } // acknowledge the packet response.setType(QXmppIq::Result); client()->sendPacket(response); // check received data job->checkData(); } void QXmppTransferManager::ibbDataIqReceived(const QXmppIbbDataIq &iq) { QXmppIq response; response.setTo(iq.from()); response.setId(iq.id()); QXmppTransferIncomingJob *job = d->getIncomingJobBySid(iq.from(), iq.sid()); if (!job || job->method() != QXmppTransferJob::InBandMethod || job->state() != QXmppTransferJob::TransferState) { // the job is unknown, cancel it QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::ItemNotFound); response.setType(QXmppIq::Error); response.setError(error); client()->sendPacket(response); return; } if (iq.sequence() != job->d->ibbSequence) { // the packet is out of sequence QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::UnexpectedRequest); response.setType(QXmppIq::Error); response.setError(error); client()->sendPacket(response); return; } // write data job->writeData(iq.payload()); job->d->ibbSequence++; // acknowledge the packet response.setType(QXmppIq::Result); client()->sendPacket(response); } void QXmppTransferManager::ibbOpenIqReceived(const QXmppIbbOpenIq &iq) { QXmppIq response; response.setTo(iq.from()); response.setId(iq.id()); QXmppTransferJob *job = d->getIncomingJobBySid(iq.from(), iq.sid()); if (!job || job->method() != QXmppTransferJob::InBandMethod) { // the job is unknown, cancel it QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::ItemNotFound); response.setType(QXmppIq::Error); response.setError(error); client()->sendPacket(response); return; } if (iq.blockSize() > d->ibbBlockSize) { // we prefer a smaller block size QXmppStanza::Error error(QXmppStanza::Error::Modify, QXmppStanza::Error::ResourceConstraint); response.setType(QXmppIq::Error); response.setError(error); client()->sendPacket(response); return; } job->d->blockSize = iq.blockSize(); job->setState(QXmppTransferJob::TransferState); // accept transfer response.setType(QXmppIq::Result); client()->sendPacket(response); } void QXmppTransferManager::ibbResponseReceived(const QXmppIq &iq) { QXmppTransferJob *job = d->getOutgoingJobByRequestId(iq.from(), iq.id()); if (!job || job->method() != QXmppTransferJob::InBandMethod || job->state() == QXmppTransferJob::FinishedState) return; // if the IO device is closed, do nothing if (!job->d->iodevice->isOpen()) return; if (iq.type() == QXmppIq::Result) { const QByteArray buffer = job->d->iodevice->read(job->d->blockSize); job->setState(QXmppTransferJob::TransferState); if (buffer.size()) { // send next data block QXmppIbbDataIq dataIq; dataIq.setTo(job->d->jid); dataIq.setSid(job->d->sid); dataIq.setSequence(job->d->ibbSequence++); dataIq.setPayload(buffer); job->d->requestId = dataIq.id(); client()->sendPacket(dataIq); job->d->done += buffer.size(); job->progress(job->d->done, job->fileSize()); } else { // close the bytestream QXmppIbbCloseIq closeIq; closeIq.setTo(job->d->jid); closeIq.setSid(job->d->sid); job->d->requestId = closeIq.id(); client()->sendPacket(closeIq); job->terminate(QXmppTransferJob::NoError); } } else if (iq.type() == QXmppIq::Error) { // close the bytestream QXmppIbbCloseIq closeIq; closeIq.setTo(job->d->jid); closeIq.setSid(job->d->sid); job->d->requestId = closeIq.id(); client()->sendPacket(closeIq); job->terminate(QXmppTransferJob::ProtocolError); } } void QXmppTransferManager::_q_iqReceived(const QXmppIq &iq) { bool check; Q_UNUSED(check); foreach (QXmppTransferJob *ptr, d->jobs) { // handle IQ from proxy if (ptr->direction() == QXmppTransferJob::OutgoingDirection && ptr->d->socksProxy.jid() == iq.from() && ptr->d->requestId == iq.id()) { QXmppTransferOutgoingJob *job = static_cast(ptr); if (job->d->socksSocket) { // proxy connection activation result if (iq.type() == QXmppIq::Result) { // proxy stream activated, start sending data job->startSending(); } else if (iq.type() == QXmppIq::Error) { // proxy stream not activated, terminate warning("Could not activate SOCKS5 proxy bytestream"); job->terminate(QXmppTransferJob::ProtocolError); } } else { // we could not get host/port from proxy, procede without a proxy if (iq.type() == QXmppIq::Error) socksServerSendOffer(job); } return; } // handle IQ from peer else if (ptr->d->jid == iq.from() && ptr->d->requestId == iq.id()) { QXmppTransferJob *job = ptr; if (job->direction() == QXmppTransferJob::OutgoingDirection && job->method() == QXmppTransferJob::InBandMethod) { ibbResponseReceived(iq); return; } else if (job->direction() == QXmppTransferJob::IncomingDirection && job->method() == QXmppTransferJob::SocksMethod) { byteStreamResponseReceived(iq); return; } else if (job->direction() == QXmppTransferJob::OutgoingDirection && iq.type() == QXmppIq::Error) { // remote party cancelled stream initiation job->terminate(QXmppTransferJob::AbortError); return; } } } } void QXmppTransferManager::_q_jobDestroyed(QObject *object) { d->jobs.removeAll(static_cast(object)); } void QXmppTransferManager::_q_jobError(QXmppTransferJob::Error error) { QXmppTransferJob *job = qobject_cast(sender()); if (!job || !d->jobs.contains(job)) return; if (job->direction() == QXmppTransferJob::OutgoingDirection && job->method() == QXmppTransferJob::InBandMethod && error == QXmppTransferJob::AbortError) { // close the bytestream QXmppIbbCloseIq closeIq; closeIq.setTo(job->d->jid); closeIq.setSid(job->d->sid); job->d->requestId = closeIq.id(); client()->sendPacket(closeIq); } } void QXmppTransferManager::_q_jobFinished() { QXmppTransferJob *job = qobject_cast(sender()); if (!job || !d->jobs.contains(job)) return; emit jobFinished(job); } void QXmppTransferManager::_q_jobStateChanged(QXmppTransferJob::State state) { bool check; Q_UNUSED(check); QXmppTransferJob *job = qobject_cast(sender()); if (!job || !d->jobs.contains(job)) return; if (job->direction() != QXmppTransferJob::IncomingDirection) return; // disconnect from the signal disconnect(job, SIGNAL(stateChanged(QXmppTransferJob::State)), this, SLOT(_q_jobStateChanged(QXmppTransferJob::State))); // the job was refused by the local party if (state != QXmppTransferJob::StartState || !job->d->iodevice || !job->d->iodevice->isWritable()) { QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::Forbidden); error.setCode(403); QXmppIq response; response.setTo(job->jid()); response.setId(job->d->offerId); response.setType(QXmppIq::Error); response.setError(error); client()->sendPacket(response); job->terminate(QXmppTransferJob::AbortError); return; } // the job was accepted by the local party check = connect(job, SIGNAL(error(QXmppTransferJob::Error)), this, SLOT(_q_jobError(QXmppTransferJob::Error))); Q_ASSERT(check); QXmppDataForm form; form.setType(QXmppDataForm::Submit); QXmppDataForm::Field methodField(QXmppDataForm::Field::ListSingleField); methodField.setKey("stream-method"); if (job->method() == QXmppTransferJob::InBandMethod) methodField.setValue(ns_ibb); else if (job->method() == QXmppTransferJob::SocksMethod) methodField.setValue(ns_bytestreams); form.setFields(QList() << methodField); QXmppStreamInitiationIq response; response.setTo(job->jid()); response.setId(job->d->offerId); response.setType(QXmppIq::Result); response.setProfile(QXmppStreamInitiationIq::FileTransfer); response.setFeatureForm(form); client()->sendPacket(response); // notify user emit jobStarted(job); } /// Sends the file at \a filePath to a remote party. /// /// The remote party will be given the choice to accept or refuse the transfer. /// /// Returns 0 if the \a jid is not valid or if the file at \a filePath cannot be read. /// /// \note The recipient's \a jid must be a full JID with a resource, for instance "user@host/resource". /// QXmppTransferJob *QXmppTransferManager::sendFile(const QString &jid, const QString &filePath, const QString &description) { if (QXmppUtils::jidToResource(jid).isEmpty()) { warning("The file recipient's JID must be a full JID"); return 0; } QFileInfo info(filePath); QXmppTransferFileInfo fileInfo; fileInfo.setDate(info.lastModified()); fileInfo.setName(info.fileName()); fileInfo.setSize(info.size()); fileInfo.setDescription(description); // open file QIODevice *device = new QFile(filePath, this); if (!device->open(QIODevice::ReadOnly)) { warning(QString("Could not read from %1").arg(filePath)); delete device; device = 0; } // hash file if (device && !device->isSequential()) { QCryptographicHash hash(QCryptographicHash::Md5); QByteArray buffer; while (device->bytesAvailable()) { buffer = device->read(16384); hash.addData(buffer); } device->reset(); fileInfo.setHash(hash.result()); } // create job QXmppTransferJob *job = sendFile(jid, device, fileInfo); job->setLocalFileUrl(QUrl::fromLocalFile(filePath)); job->d->deviceIsOwn = true; return job; } /// Sends the file in \a device to a remote party. /// /// The remote party will be given the choice to accept or refuse the transfer. /// /// Returns 0 if the \a jid is not valid. /// /// \note The recipient's \a jid must be a full JID with a resource, for instance "user@host/resource". /// \note The ownership of the \a device should be managed by the caller. /// QXmppTransferJob *QXmppTransferManager::sendFile(const QString &jid, QIODevice *device, const QXmppTransferFileInfo &fileInfo, const QString &sid) { bool check; Q_UNUSED(check); if (QXmppUtils::jidToResource(jid).isEmpty()) { warning("The file recipient's JID must be a full JID"); return 0; } QXmppTransferOutgoingJob *job = new QXmppTransferOutgoingJob(jid, client(), this); if (sid.isEmpty()) job->d->sid = QXmppUtils::generateStanzaHash(); else job->d->sid = sid; job->d->fileInfo = fileInfo; job->d->iodevice = device; // check file is open if (!device || !device->isReadable()) { job->terminate(QXmppTransferJob::FileAccessError); return job; } // check we support some methods if (!d->supportedMethods) { job->terminate(QXmppTransferJob::ProtocolError); return job; } // collect supported stream methods QXmppDataForm form; form.setType(QXmppDataForm::Form); QXmppDataForm::Field methodField(QXmppDataForm::Field::ListSingleField); methodField.setKey("stream-method"); if (d->supportedMethods & QXmppTransferJob::InBandMethod) methodField.setOptions(methodField.options() << qMakePair(QString(), QString::fromLatin1(ns_ibb))); if (d->supportedMethods & QXmppTransferJob::SocksMethod) methodField.setOptions(methodField.options() << qMakePair(QString(), QString::fromLatin1(ns_bytestreams))); form.setFields(QList() << methodField); // start job d->jobs.append(job); check = connect(job, SIGNAL(destroyed(QObject*)), this, SLOT(_q_jobDestroyed(QObject*))); Q_ASSERT(check); check = connect(job, SIGNAL(error(QXmppTransferJob::Error)), this, SLOT(_q_jobError(QXmppTransferJob::Error))); Q_ASSERT(check); check = connect(job, SIGNAL(finished()), this, SLOT(_q_jobFinished())); Q_ASSERT(check); QXmppStreamInitiationIq request; request.setType(QXmppIq::Set); request.setTo(jid); request.setProfile(QXmppStreamInitiationIq::FileTransfer); request.setFileInfo(job->d->fileInfo); request.setFeatureForm(form); request.setSiId(job->d->sid); job->d->requestId = request.id(); client()->sendPacket(request); // notify user emit jobStarted(job); return job; } void QXmppTransferManager::_q_socksServerConnected(QTcpSocket *socket, const QString &hostName, quint16 port) { const QString ownJid = client()->configuration().jid(); foreach (QXmppTransferJob *job, d->jobs) { if (hostName == streamHash(job->d->sid, ownJid, job->jid()) && port == 0) { job->d->socksSocket = socket; return; } } warning("QXmppSocksServer got a connection for a unknown stream"); socket->close(); } void QXmppTransferManager::socksServerSendOffer(QXmppTransferJob *job) { const QString ownJid = client()->configuration().jid(); QList streamHosts; // discover local IPs if (!d->proxyOnly) { foreach (const QHostAddress &address, QXmppIceComponent::discoverAddresses()) { QXmppByteStreamIq::StreamHost streamHost; streamHost.setJid(ownJid); streamHost.setHost(address.toString()); streamHost.setPort(d->socksServer->serverPort()); streamHosts.append(streamHost); } } // add proxy if (!job->d->socksProxy.jid().isEmpty()) streamHosts.append(job->d->socksProxy); // check we have some stream hosts if (!streamHosts.size()) { warning("Could not determine local stream hosts"); job->terminate(QXmppTransferJob::ProtocolError); return; } // send offer QXmppByteStreamIq streamIq; streamIq.setType(QXmppIq::Set); streamIq.setTo(job->d->jid); streamIq.setSid(job->d->sid); streamIq.setStreamHosts(streamHosts); job->d->requestId = streamIq.id(); client()->sendPacket(streamIq); } void QXmppTransferManager::streamInitiationIqReceived(const QXmppStreamInitiationIq &iq) { if (iq.type() == QXmppIq::Result) streamInitiationResultReceived(iq); else if (iq.type() == QXmppIq::Set) streamInitiationSetReceived(iq); } // The remote party has accepted an outgoing transfer. void QXmppTransferManager::streamInitiationResultReceived(const QXmppStreamInitiationIq &iq) { QXmppTransferJob *job = d->getOutgoingJobByRequestId(iq.from(), iq.id()); if (!job || job->state() != QXmppTransferJob::OfferState) return; foreach (const QXmppDataForm::Field &field, iq.featureForm().fields()) { if (field.key() == "stream-method") { if ((field.value().toString() == ns_ibb) && (d->supportedMethods & QXmppTransferJob::InBandMethod)) job->d->method = QXmppTransferJob::InBandMethod; else if ((field.value().toString() == ns_bytestreams) && (d->supportedMethods & QXmppTransferJob::SocksMethod)) job->d->method = QXmppTransferJob::SocksMethod; } } // remote party accepted stream initiation job->setState(QXmppTransferJob::StartState); if (job->method() == QXmppTransferJob::InBandMethod) { // lower block size for IBB job->d->blockSize = d->ibbBlockSize; QXmppIbbOpenIq openIq; openIq.setTo(job->d->jid); openIq.setSid(job->d->sid); openIq.setBlockSize(job->d->blockSize); job->d->requestId = openIq.id(); client()->sendPacket(openIq); } else if (job->method() == QXmppTransferJob::SocksMethod) { if (!d->proxy.isEmpty()) { job->d->socksProxy.setJid(d->proxy); // query proxy QXmppByteStreamIq streamIq; streamIq.setType(QXmppIq::Get); streamIq.setTo(job->d->socksProxy.jid()); streamIq.setSid(job->d->sid); job->d->requestId = streamIq.id(); client()->sendPacket(streamIq); } else { socksServerSendOffer(job); } } else { warning("QXmppTransferManager received an unsupported method"); job->terminate(QXmppTransferJob::ProtocolError); } } void QXmppTransferManager::streamInitiationSetReceived(const QXmppStreamInitiationIq &iq) { bool check; Q_UNUSED(check); QXmppIq response; response.setTo(iq.from()); response.setId(iq.id()); // check we support the profile if (iq.profile() != QXmppStreamInitiationIq::FileTransfer) { // FIXME : we should add: // QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::BadRequest); error.setCode(400); response.setType(QXmppIq::Error); response.setError(error); client()->sendPacket(response); return; } // check there is a receiver connected to the fileReceived() signal if (!receivers(SIGNAL(fileReceived(QXmppTransferJob*)))) { QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::Forbidden); error.setCode(403); response.setType(QXmppIq::Error); response.setError(error); client()->sendPacket(response); return; } // check the stream type QXmppTransferIncomingJob *job = new QXmppTransferIncomingJob(iq.from(), client(), this); int offeredMethods = QXmppTransferJob::NoMethod; job->d->offerId = iq.id(); job->d->sid = iq.siId(); job->d->mimeType = iq.mimeType(); job->d->fileInfo = iq.fileInfo(); foreach (const QXmppDataForm::Field &field, iq.featureForm().fields()) { if (field.key() == "stream-method") { QPair option; foreach (option, field.options()) { if (option.second == ns_ibb) offeredMethods = offeredMethods | QXmppTransferJob::InBandMethod; else if (option.second == ns_bytestreams) offeredMethods = offeredMethods | QXmppTransferJob::SocksMethod; } } } // select a method supported by both parties int sharedMethods = (offeredMethods & d->supportedMethods); if (sharedMethods & QXmppTransferJob::SocksMethod) job->d->method = QXmppTransferJob::SocksMethod; else if (sharedMethods & QXmppTransferJob::InBandMethod) job->d->method = QXmppTransferJob::InBandMethod; else { // FIXME : we should add: // QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::BadRequest); error.setCode(400); response.setType(QXmppIq::Error); response.setError(error); client()->sendPacket(response); delete job; return; } // register job d->jobs.append(job); check = connect(job, SIGNAL(destroyed(QObject*)), this, SLOT(_q_jobDestroyed(QObject*))); Q_ASSERT(check); check = connect(job, SIGNAL(finished()), this, SLOT(_q_jobFinished())); Q_ASSERT(check); check = connect(job, SIGNAL(stateChanged(QXmppTransferJob::State)), this, SLOT(_q_jobStateChanged(QXmppTransferJob::State))); Q_ASSERT(check); // allow user to accept or decline the job emit fileReceived(job); } /// Return the JID of the bytestream proxy to use for /// outgoing transfers. /// QString QXmppTransferManager::proxy() const { return d->proxy; } /// Set the JID of the SOCKS5 bytestream proxy to use for /// outgoing transfers. /// /// If you set a proxy, when you send a file the proxy will /// be offered to the recipient in addition to your own IP /// addresses. /// void QXmppTransferManager::setProxy(const QString &proxyJid) { d->proxy = proxyJid; } /// Return whether the proxy will systematically be used for /// outgoing SOCKS5 bytestream transfers. /// bool QXmppTransferManager::proxyOnly() const { return d->proxyOnly; } /// Set whether the proxy should systematically be used for /// outgoing SOCKS5 bytestream transfers. /// /// \note If you set this to true and do not provide a proxy /// using setProxy(), your outgoing transfers will fail! /// void QXmppTransferManager::setProxyOnly(bool proxyOnly) { d->proxyOnly = proxyOnly; } /// Return the supported stream methods. /// /// The methods are a combination of zero or more QXmppTransferJob::Method. /// QXmppTransferJob::Methods QXmppTransferManager::supportedMethods() const { return d->supportedMethods; } /// Set the supported stream methods. This allows you to selectively /// enable or disable stream methods (In-Band or SOCKS5 bytestreams). /// /// The methods argument is a combination of zero or more /// QXmppTransferJob::Method. /// void QXmppTransferManager::setSupportedMethods(QXmppTransferJob::Methods methods) { d->supportedMethods = methods; } qxmpp-0.9.3/src/client/QXmppTransferManager.h000066400000000000000000000230361263006255200211600ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPTRANSFERMANAGER_H #define QXMPPTRANSFERMANAGER_H #include #include #include #include #include "QXmppClientExtension.h" class QTcpSocket; class QXmppByteStreamIq; class QXmppIbbCloseIq; class QXmppIbbDataIq; class QXmppIbbOpenIq; class QXmppIq; class QXmppStreamInitiationIq; class QXmppTransferFileInfoPrivate; class QXmppTransferJobPrivate; class QXmppTransferManager; class QXmppTransferManagerPrivate; class QXMPP_EXPORT QXmppTransferFileInfo { public: QXmppTransferFileInfo(); QXmppTransferFileInfo(const QXmppTransferFileInfo &other); ~QXmppTransferFileInfo(); QDateTime date() const; void setDate(const QDateTime &date); QByteArray hash() const; void setHash(const QByteArray &hash); QString name() const; void setName(const QString &name); QString description() const; void setDescription(const QString &description); qint64 size() const; void setSize(qint64 size); bool isNull() const; QXmppTransferFileInfo& operator=(const QXmppTransferFileInfo &other); bool operator==(const QXmppTransferFileInfo &other) const; /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; /// \endcond private: QSharedDataPointer d; }; /// \brief The QXmppTransferJob class represents a single file transfer job. /// /// \sa QXmppTransferManager /// class QXMPP_EXPORT QXmppTransferJob : public QXmppLoggable { Q_OBJECT Q_ENUMS(Direction Error State) Q_FLAGS(Method Methods) Q_PROPERTY(Direction direction READ direction CONSTANT) Q_PROPERTY(QUrl localFileUrl READ localFileUrl WRITE setLocalFileUrl NOTIFY localFileUrlChanged) Q_PROPERTY(QString jid READ jid CONSTANT) Q_PROPERTY(Method method READ method CONSTANT) Q_PROPERTY(State state READ state NOTIFY stateChanged) Q_PROPERTY(QString fileName READ fileName CONSTANT) Q_PROPERTY(qint64 fileSize READ fileSize CONSTANT) public: /// This enum is used to describe the direction of a transfer job. enum Direction { IncomingDirection, ///< The file is being received. OutgoingDirection ///< The file is being sent. }; /// This enum is used to describe the type of error encountered by a transfer job. enum Error { NoError = 0, ///< No error occurred. AbortError, ///< The file transfer was aborted. FileAccessError, ///< An error was encountered trying to access a local file. FileCorruptError, ///< The file is corrupt: the file size or hash do not match. ProtocolError ///< An error was encountered in the file transfer protocol. }; /// This enum is used to describe a transfer method. enum Method { NoMethod = 0, ///< No transfer method. InBandMethod = 1, ///< XEP-0047: In-Band Bytestreams SocksMethod = 2, ///< XEP-0065: SOCKS5 Bytestreams AnyMethod = 3 ///< Any supported transfer method. }; Q_DECLARE_FLAGS(Methods, Method) /// This enum is used to describe the state of a transfer job. enum State { OfferState = 0, ///< The transfer is being offered to the remote party. StartState = 1, ///< The transfer is being connected. TransferState = 2, ///< The transfer is ongoing. FinishedState = 3 ///< The transfer is finished. }; ~QXmppTransferJob(); QXmppTransferJob::Direction direction() const; QXmppTransferJob::Error error() const; QString jid() const; QXmppTransferJob::Method method() const; QString sid() const; qint64 speed() const; QXmppTransferJob::State state() const; // XEP-0096 : File transfer QXmppTransferFileInfo fileInfo() const; QUrl localFileUrl() const; void setLocalFileUrl(const QUrl &localFileUrl); /// \cond QDateTime fileDate() const; QByteArray fileHash() const; QString fileName() const; qint64 fileSize() const; /// \endcond signals: /// This signal is emitted when an error is encountered while /// processing the transfer job. void error(QXmppTransferJob::Error error); /// This signal is emitted when the transfer job is finished. /// /// You can determine if the job completed successfully by testing whether /// error() returns QXmppTransferJob::NoError. /// /// Note: Do not delete the job in the slot connected to this signal, /// instead use deleteLater(). void finished(); /// This signal is emitted when the local file URL changes. void localFileUrlChanged(const QUrl &localFileUrl); /// This signal is emitted to indicate the progress of this transfer job. void progress(qint64 done, qint64 total); /// This signal is emitted when the transfer job changes state. void stateChanged(QXmppTransferJob::State state); public slots: void abort(); void accept(const QString &filePath); void accept(QIODevice *output); private slots: void _q_terminated(); private: QXmppTransferJob(const QString &jid, QXmppTransferJob::Direction direction, QXmppClient *client, QObject *parent); void setState(QXmppTransferJob::State state); void terminate(QXmppTransferJob::Error error); QXmppTransferJobPrivate *const d; friend class QXmppTransferManager; friend class QXmppTransferManagerPrivate; friend class QXmppTransferIncomingJob; friend class QXmppTransferOutgoingJob; }; /// \brief The QXmppTransferManager class provides support for sending and /// receiving files. /// /// Stream initiation is performed as described in XEP-0095: Stream Initiation /// and XEP-0096: SI File Transfer. The actual file transfer is then performed /// using either XEP-0065: SOCKS5 Bytestreams or XEP-0047: In-Band Bytestreams. /// /// To make use of this manager, you need to instantiate it and load it into /// the QXmppClient instance as follows: /// /// \code /// QXmppTransferManager *manager = new QXmppTransferManager; /// client->addExtension(manager); /// \endcode /// /// \ingroup Managers class QXMPP_EXPORT QXmppTransferManager : public QXmppClientExtension { Q_OBJECT Q_PROPERTY(QString proxy READ proxy WRITE setProxy) Q_PROPERTY(bool proxyOnly READ proxyOnly WRITE setProxyOnly) Q_PROPERTY(QXmppTransferJob::Methods supportedMethods READ supportedMethods WRITE setSupportedMethods) public: QXmppTransferManager(); ~QXmppTransferManager(); QString proxy() const; void setProxy(const QString &proxyJid); bool proxyOnly() const; void setProxyOnly(bool proxyOnly); QXmppTransferJob::Methods supportedMethods() const; void setSupportedMethods(QXmppTransferJob::Methods methods); /// \cond QStringList discoveryFeatures() const; bool handleStanza(const QDomElement &element); /// \endcond signals: /// This signal is emitted when a new file transfer offer is received. /// /// To accept the transfer job, call the job's QXmppTransferJob::accept() method. /// To refuse the transfer job, call the job's QXmppTransferJob::abort() method. void fileReceived(QXmppTransferJob *job); /// This signal is emitted whenever a transfer job is started. void jobStarted(QXmppTransferJob *job); /// This signal is emitted whenever a transfer job is finished. /// /// \sa QXmppTransferJob::finished() void jobFinished(QXmppTransferJob *job); public slots: QXmppTransferJob *sendFile(const QString &jid, const QString &filePath, const QString &description = QString()); QXmppTransferJob *sendFile(const QString &jid, QIODevice *device, const QXmppTransferFileInfo &fileInfo, const QString &sid = QString()); protected: /// \cond void setClient(QXmppClient* client); /// \endcond private slots: void _q_iqReceived(const QXmppIq&); void _q_jobDestroyed(QObject *object); void _q_jobError(QXmppTransferJob::Error error); void _q_jobFinished(); void _q_jobStateChanged(QXmppTransferJob::State state); void _q_socksServerConnected(QTcpSocket *socket, const QString &hostName, quint16 port); private: QXmppTransferManagerPrivate *d; void byteStreamIqReceived(const QXmppByteStreamIq&); void byteStreamResponseReceived(const QXmppIq&); void byteStreamResultReceived(const QXmppByteStreamIq&); void byteStreamSetReceived(const QXmppByteStreamIq&); void ibbCloseIqReceived(const QXmppIbbCloseIq&); void ibbDataIqReceived(const QXmppIbbDataIq&); void ibbOpenIqReceived(const QXmppIbbOpenIq&); void ibbResponseReceived(const QXmppIq&); void streamInitiationIqReceived(const QXmppStreamInitiationIq&); void streamInitiationResultReceived(const QXmppStreamInitiationIq&); void streamInitiationSetReceived(const QXmppStreamInitiationIq&); void socksServerSendOffer(QXmppTransferJob *job); friend class QXmppTransferManagerPrivate; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QXmppTransferJob::Methods) #endif qxmpp-0.9.3/src/client/QXmppTransferManager_p.h000066400000000000000000000042211263006255200214720ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPTRANSFERMANAGER_P_H #define QXMPPTRANSFERMANAGER_P_H #include "QXmppByteStreamIq.h" #include "QXmppTransferManager.h" // // W A R N I N G // ------------- // // This file is not part of the QXmpp API. It exists for the convenience // of the QXmppTransferManager class. This header file may change from // version to version without notice, or even be removed. // // We mean it. // class QTimer; class QXmppSocksClient; class QXmppTransferIncomingJob : public QXmppTransferJob { Q_OBJECT public: QXmppTransferIncomingJob(const QString &jid, QXmppClient *client, QObject *parent); void checkData(); void connectToHosts(const QXmppByteStreamIq &iq); bool writeData(const QByteArray &data); private slots: void _q_candidateDisconnected(); void _q_candidateReady(); void _q_disconnected(); void _q_receiveData(); private: void connectToNextHost(); QXmppByteStreamIq::StreamHost m_candidateHost; QXmppSocksClient *m_candidateClient; QTimer *m_candidateTimer; QList m_streamCandidates; QString m_streamOfferId; QString m_streamOfferFrom; }; class QXmppTransferOutgoingJob : public QXmppTransferJob { Q_OBJECT public: QXmppTransferOutgoingJob(const QString &jid, QXmppClient *client, QObject *parent); void connectToProxy(); void startSending(); private slots: void _q_disconnected(); void _q_proxyReady(); void _q_sendData(); }; #endif qxmpp-0.9.3/src/client/QXmppVCardManager.cpp000066400000000000000000000060671263006255200207330ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppClient.h" #include "QXmppConstants.h" #include "QXmppUtils.h" #include "QXmppVCardIq.h" #include "QXmppVCardManager.h" class QXmppVCardManagerPrivate { public: QXmppVCardIq clientVCard; bool isClientVCardReceived; }; QXmppVCardManager::QXmppVCardManager() : d(new QXmppVCardManagerPrivate) { d->isClientVCardReceived = false; } QXmppVCardManager::~QXmppVCardManager() { delete d; } /// This function requests the server for vCard of the specified jid. /// Once received the signal vCardReceived() is emitted. /// /// \param jid Jid of the specific entry in the roster /// QString QXmppVCardManager::requestVCard(const QString& jid) { QXmppVCardIq request(jid); if(client()->sendPacket(request)) return request.id(); else return QString(); } /// Returns the vCard of the connected client. /// /// \return QXmppVCard /// const QXmppVCardIq& QXmppVCardManager::clientVCard() const { return d->clientVCard; } /// Sets the vCard of the connected client. /// /// \param clientVCard QXmppVCard /// void QXmppVCardManager::setClientVCard(const QXmppVCardIq& clientVCard) { d->clientVCard = clientVCard; d->clientVCard.setTo(""); d->clientVCard.setFrom(""); d->clientVCard.setType(QXmppIq::Set); client()->sendPacket(d->clientVCard); } /// This function requests the server for vCard of the connected user itself. /// Once received the signal clientVCardReceived() is emitted. Received vCard /// can be get using clientVCard(). QString QXmppVCardManager::requestClientVCard() { return requestVCard(); } /// Returns true if vCard of the connected client has been /// received else false. /// /// \return bool /// bool QXmppVCardManager::isClientVCardReceived() const { return d->isClientVCardReceived; } /// \cond QStringList QXmppVCardManager::discoveryFeatures() const { // XEP-0054: vcard-temp return QStringList() << ns_vcard; } bool QXmppVCardManager::handleStanza(const QDomElement &element) { if(element.tagName() == "iq" && QXmppVCardIq::isVCard(element)) { QXmppVCardIq vCardIq; vCardIq.parse(element); if (vCardIq.from().isEmpty()) { d->clientVCard = vCardIq; d->isClientVCardReceived = true; emit clientVCardReceived(); } emit vCardReceived(vCardIq); return true; } return false; } /// \endcond qxmpp-0.9.3/src/client/QXmppVCardManager.h000066400000000000000000000053321263006255200203720ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 QXMPPVCARDMANAGER_H #define QXMPPVCARDMANAGER_H #include "QXmppClientExtension.h" class QXmppVCardIq; class QXmppVCardManagerPrivate; /// \brief The QXmppVCardManager class gets/sets XMPP vCards. It is an /// implementation of XEP-0054: vcard-temp. /// /// \note It's object should not be created using it's constructor. Instead /// QXmppClient::vCardManager() should be used to get the reference of instantiated /// object this class. /// /// Getting vCards of entries in Roster:
/// It doesn't store vCards of the JIDs in the roster of connected user. Instead /// client has to request for a particular vCard using requestVCard(). And connect to /// the signal vCardReceived() to get the requested vCard. /// /// Getting vCard of the connected client:
/// For getting the vCard of the connected user itself. Client can call requestClientVCard() /// and on the signal clientVCardReceived() it can get its vCard using clientVCard(). /// /// Setting vCard of the client:
/// Using setClientVCard() client can set its vCard. /// /// \note Client can't set/change vCards of roster entries. /// /// \ingroup Managers class QXMPP_EXPORT QXmppVCardManager : public QXmppClientExtension { Q_OBJECT public: QXmppVCardManager(); ~QXmppVCardManager(); QString requestVCard(const QString& bareJid = QString()); const QXmppVCardIq& clientVCard() const; void setClientVCard(const QXmppVCardIq&); QString requestClientVCard(); bool isClientVCardReceived() const; /// \cond QStringList discoveryFeatures() const; bool handleStanza(const QDomElement &element); /// \endcond signals: /// This signal is emitted when the requested vCard is received /// after calling the requestVCard() function. void vCardReceived(const QXmppVCardIq&); /// This signal is emitted when the client's vCard is received /// after calling the requestClientVCard() function. void clientVCardReceived(); private: QXmppVCardManagerPrivate *d; }; #endif // QXMPPVCARDMANAGER_H qxmpp-0.9.3/src/client/QXmppVersionManager.cpp000066400000000000000000000103151263006255200213500ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppClient.h" #include "QXmppConstants.h" #include "QXmppGlobal.h" #include "QXmppVersionManager.h" #include "QXmppVersionIq.h" class QXmppVersionManagerPrivate { public: QString clientName; QString clientVersion; QString clientOs; }; QXmppVersionManager::QXmppVersionManager() : d(new QXmppVersionManagerPrivate) { d->clientName = qApp->applicationName(); if (d->clientName.isEmpty()) d->clientName = "Based on QXmpp"; #if defined(Q_OS_LINUX) d->clientOs = QString::fromLatin1("Linux"); #elif defined(Q_OS_MAC) d->clientOs = QString::fromLatin1("Mac OS"); #elif defined(Q_OS_SYMBIAN) d->clientOs = QString::fromLatin1("Symbian"); #elif defined(Q_OS_WIN) d->clientOs = QString::fromLatin1("Windows"); #endif d->clientVersion = qApp->applicationVersion(); if (d->clientVersion.isEmpty()) d->clientVersion = QXmppVersion(); } QXmppVersionManager::~QXmppVersionManager() { delete d; } /// Request version information from the specified XMPP entity. /// /// \param jid QString QXmppVersionManager::requestVersion(const QString& jid) { QXmppVersionIq request; request.setType(QXmppIq::Get); request.setTo(jid); if(client()->sendPacket(request)) return request.id(); else return QString(); } /// Sets the local XMPP client's name. /// /// \param name void QXmppVersionManager::setClientName(const QString& name) { d->clientName = name; } /// Sets the local XMPP client's version. /// /// \param version void QXmppVersionManager::setClientVersion(const QString& version) { d->clientVersion = version; } /// Sets the local XMPP client's operating system. /// /// \param os void QXmppVersionManager::setClientOs(const QString& os) { d->clientOs = os; } /// Returns the local XMPP client's name. /// /// By default this is set to the QApplication::applicationName(), or /// "Based on QXmpp" if not specified. QString QXmppVersionManager::clientName() const { return d->clientName; } /// Returns the local XMPP client's version. /// /// By default this is set to QApplication::applicationVersion(), or /// QXmpp's version if not specified. QString QXmppVersionManager::clientVersion() const { return d->clientVersion; } /// Returns the local XMPP client's operating system. /// /// By default this is "Linux", "Mac OS", "Symbian" or "Windows" depending /// on the platform QXmpp was compiled for. QString QXmppVersionManager::clientOs() const { return d->clientOs; } /// \cond QStringList QXmppVersionManager::discoveryFeatures() const { // XEP-0092: Software Version return QStringList() << ns_version; } bool QXmppVersionManager::handleStanza(const QDomElement &element) { if (element.tagName() == "iq" && QXmppVersionIq::isVersionIq(element)) { QXmppVersionIq versionIq; versionIq.parse(element); if (versionIq.type() == QXmppIq::Get) { // respond to query QXmppVersionIq responseIq; responseIq.setType(QXmppIq::Result); responseIq.setId(versionIq.id()); responseIq.setTo(versionIq.from()); responseIq.setName(clientName()); responseIq.setVersion(clientVersion()); responseIq.setOs(clientOs()); client()->sendPacket(responseIq); } else if (versionIq.type() == QXmppIq::Result) { // emit response emit versionReceived(versionIq); } return true; } return false; } /// \endcond qxmpp-0.9.3/src/client/QXmppVersionManager.h000066400000000000000000000034151263006255200210200ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 QXMPPVERSIONMANAGER_H #define QXMPPVERSIONMANAGER_H #include "QXmppClientExtension.h" class QXmppVersionIq; class QXmppVersionManagerPrivate; /// \brief The QXmppVersionManager class makes it possible to request for /// the software version of an entity as defined by XEP-0092: Software Version. /// /// \ingroup Managers class QXMPP_EXPORT QXmppVersionManager : public QXmppClientExtension { Q_OBJECT public: QXmppVersionManager(); ~QXmppVersionManager(); QString requestVersion(const QString& jid); void setClientName(const QString&); void setClientVersion(const QString&); void setClientOs(const QString&); QString clientName() const; QString clientVersion() const; QString clientOs() const; /// \cond QStringList discoveryFeatures() const; bool handleStanza(const QDomElement &element); /// \endcond signals: /// \brief This signal is emitted when a version response is received. void versionReceived(const QXmppVersionIq&); private: QXmppVersionManagerPrivate *d; }; #endif // QXMPPVERSIONMANAGER_H qxmpp-0.9.3/src/client/client.pri000066400000000000000000000025251263006255200167340ustar00rootroot00000000000000# Header files INSTALL_HEADERS += \ client/QXmppArchiveManager.h \ client/QXmppBookmarkManager.h \ client/QXmppCallManager.h \ client/QXmppClient.h \ client/QXmppClientExtension.h \ client/QXmppConfiguration.h \ client/QXmppDiscoveryManager.h \ client/QXmppEntityTimeManager.h \ client/QXmppInvokable.h \ client/QXmppMessageReceiptManager.h \ client/QXmppMucManager.h \ client/QXmppOutgoingClient.h \ client/QXmppRemoteMethod.h \ client/QXmppRosterManager.h \ client/QXmppRpcManager.h \ client/QXmppTransferManager.h \ client/QXmppTransferManager_p.h \ client/QXmppVCardManager.h \ client/QXmppVersionManager.h # Source files SOURCES += \ client/QXmppDiscoveryManager.cpp \ client/QXmppArchiveManager.cpp \ client/QXmppBookmarkManager.cpp \ client/QXmppCallManager.cpp \ client/QXmppClient.cpp \ client/QXmppClientExtension.cpp \ client/QXmppConfiguration.cpp \ client/QXmppEntityTimeManager.cpp \ client/QXmppInvokable.cpp \ client/QXmppMessageReceiptManager.cpp \ client/QXmppMucManager.cpp \ client/QXmppOutgoingClient.cpp \ client/QXmppRemoteMethod.cpp \ client/QXmppRosterManager.cpp \ client/QXmppRpcManager.cpp \ client/QXmppTransferManager.cpp \ client/QXmppVCardManager.cpp \ client/QXmppVersionManager.cpp qxmpp-0.9.3/src/server/000077500000000000000000000000001263006255200147665ustar00rootroot00000000000000qxmpp-0.9.3/src/server/QXmppDialback.cpp000066400000000000000000000051411263006255200201530ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppDialback.h" #include "QXmppUtils.h" /// Constructs a QXmppDialback. QXmppDialback::QXmppDialback() : m_command(Result) { } /// Returns the dialback command. QXmppDialback::Command QXmppDialback::command() const { return m_command; } /// Sets the dialback command. /// /// \param command void QXmppDialback::setCommand(QXmppDialback::Command command) { m_command = command; } /// Returns the dialback key. QString QXmppDialback::key() const { return m_key; } /// Sets the dialback key. /// /// \param key void QXmppDialback::setKey(const QString &key) { m_key = key; } /// Returns the dialback type. QString QXmppDialback::type() const { return m_type; } /// Sets the dialback type. /// /// \param type void QXmppDialback::setType(const QString &type) { m_type = type; } /// \cond bool QXmppDialback::isDialback(const QDomElement &element) { return element.namespaceURI() == ns_server_dialback && (element.tagName() == QLatin1String("result") || element.tagName() == QLatin1String("verify")); } void QXmppDialback::parse(const QDomElement &element) { QXmppStanza::parse(element); if (element.tagName() == QLatin1String("result")) m_command = Result; else m_command = Verify; m_type = element.attribute("type"); m_key = element.text(); } void QXmppDialback::toXml(QXmlStreamWriter *xmlWriter) const { if (m_command == Result) xmlWriter->writeStartElement("db:result"); else xmlWriter->writeStartElement("db:verify"); helperToXmlAddAttribute(xmlWriter, "id", id()); helperToXmlAddAttribute(xmlWriter, "to", to()); helperToXmlAddAttribute(xmlWriter, "from", from()); helperToXmlAddAttribute(xmlWriter, "type", m_type); if (!m_key.isEmpty()) xmlWriter->writeCharacters(m_key); xmlWriter->writeEndElement(); } /// \endcond qxmpp-0.9.3/src/server/QXmppDialback.h000066400000000000000000000034341263006255200176230ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPDIALBACK_H #define QXMPPDIALBACK_H #include "QXmppStanza.h" /// \brief The QXmppDialback class represents a stanza used for the Server /// Dialback protocol as specified by XEP-0220: Server Dialback. /// /// \ingroup Stanzas class QXMPP_EXPORT QXmppDialback : public QXmppStanza { public: /// This enum is used to describe a dialback command. enum Command { Result, ///< A dialback command between the originating server ///< and the receiving server. Verify ///< A dialback command between the receiving server ///< and the authoritative server. }; QXmppDialback(); Command command() const; void setCommand(Command command); QString key() const; void setKey(const QString &key); QString type() const; void setType(const QString &type); /// \cond void parse(const QDomElement &element); void toXml(QXmlStreamWriter *writer) const; static bool isDialback(const QDomElement &element); /// \endcond private: Command m_command; QString m_key; QString m_type; }; #endif qxmpp-0.9.3/src/server/QXmppIncomingClient.cpp000066400000000000000000000355201263006255200213670ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppBindIq.h" #include "QXmppConstants.h" #include "QXmppMessage.h" #include "QXmppPasswordChecker.h" #include "QXmppSasl_p.h" #include "QXmppSessionIq.h" #include "QXmppStreamFeatures.h" #include "QXmppUtils.h" #include "QXmppIncomingClient.h" class QXmppIncomingClientPrivate { public: QXmppIncomingClientPrivate(QXmppIncomingClient *qq); QTimer *idleTimer; QString domain; QString jid; QString resource; QXmppPasswordChecker *passwordChecker; QXmppSaslServer *saslServer; void checkCredentials(const QByteArray &response); QString origin() const; private: QXmppIncomingClient *q; }; QXmppIncomingClientPrivate::QXmppIncomingClientPrivate(QXmppIncomingClient *qq) : idleTimer(0) , passwordChecker(0) , saslServer(0) , q(qq) { } void QXmppIncomingClientPrivate::checkCredentials(const QByteArray &response) { QXmppPasswordRequest request; request.setDomain(domain); request.setUsername(saslServer->username()); if (saslServer->mechanism() == "PLAIN") { request.setPassword(saslServer->password()); QXmppPasswordReply *reply = passwordChecker->checkPassword(request); reply->setParent(q); reply->setProperty("__sasl_raw", response); QObject::connect(reply, SIGNAL(finished()), q, SLOT(onPasswordReply())); } else if (saslServer->mechanism() == "DIGEST-MD5") { QXmppPasswordReply *reply = passwordChecker->getDigest(request); reply->setParent(q); reply->setProperty("__sasl_raw", response); QObject::connect(reply, SIGNAL(finished()), q, SLOT(onDigestReply())); } } QString QXmppIncomingClientPrivate::origin() const { QSslSocket *socket = q->socket(); if (socket) return socket->peerAddress().toString() + " " + QString::number(socket->peerPort()); else return ""; } /// Constructs a new incoming client stream. /// /// \param socket The socket for the XMPP stream. /// \param domain The local domain. /// \param parent The parent QObject for the stream (optional). /// QXmppIncomingClient::QXmppIncomingClient(QSslSocket *socket, const QString &domain, QObject *parent) : QXmppStream(parent) { bool check; Q_UNUSED(check); d = new QXmppIncomingClientPrivate(this); d->domain = domain; if (socket) { check = connect(socket, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); Q_ASSERT(check); setSocket(socket); } info(QString("Incoming client connection from %1").arg(d->origin())); // create inactivity timer d->idleTimer = new QTimer(this); d->idleTimer->setSingleShot(true); check = connect(d->idleTimer, SIGNAL(timeout()), this, SLOT(onTimeout())); Q_ASSERT(check); } /// Destroys the current stream. /// QXmppIncomingClient::~QXmppIncomingClient() { delete d; } /// Returns true if the socket is connected, the client is authenticated /// and a resource is bound. /// bool QXmppIncomingClient::isConnected() const { return QXmppStream::isConnected() && !d->jid.isEmpty() && !d->resource.isEmpty(); } /// Returns the client's JID. /// QString QXmppIncomingClient::jid() const { return d->jid; } /// Sets the number of seconds after which a client will be disconnected /// for inactivity. void QXmppIncomingClient::setInactivityTimeout(int secs) { d->idleTimer->stop(); d->idleTimer->setInterval(secs * 1000); if (d->idleTimer->interval()) d->idleTimer->start(); } /// Sets the password checker used to verify client credentials. /// /// \param checker /// void QXmppIncomingClient::setPasswordChecker(QXmppPasswordChecker *checker) { d->passwordChecker = checker; } /// \cond void QXmppIncomingClient::handleStream(const QDomElement &streamElement) { if (d->idleTimer->interval()) d->idleTimer->start(); if (d->saslServer != 0) { delete d->saslServer; d->saslServer = 0; } // start stream const QByteArray sessionId = QXmppUtils::generateStanzaHash().toLatin1(); QString response = QString("").arg( ns_client, ns_stream, sessionId, d->domain.toLatin1()); sendData(response.toUtf8()); // check requested domain if (streamElement.attribute("to") != d->domain) { QString response = QString("" "" "" "This server does not serve %1" "" "").arg(streamElement.attribute("to")); sendData(response.toUtf8()); disconnectFromHost(); return; } // send stream features QXmppStreamFeatures features; if (socket() && !socket()->isEncrypted() && !socket()->localCertificate().isNull() && !socket()->privateKey().isNull()) features.setTlsMode(QXmppStreamFeatures::Enabled); if (!d->jid.isEmpty()) { features.setBindMode(QXmppStreamFeatures::Required); features.setSessionMode(QXmppStreamFeatures::Enabled); } else if (d->passwordChecker) { QStringList mechanisms; mechanisms << "PLAIN"; if (d->passwordChecker->hasGetPassword()) mechanisms << "DIGEST-MD5"; features.setAuthMechanisms(mechanisms); } sendPacket(features); } void QXmppIncomingClient::handleStanza(const QDomElement &nodeRecv) { const QString ns = nodeRecv.namespaceURI(); if (d->idleTimer->interval()) d->idleTimer->start(); if (ns == ns_tls && nodeRecv.tagName() == QLatin1String("starttls")) { sendData(""); socket()->flush(); socket()->startServerEncryption(); return; } else if (ns == ns_sasl) { if (!d->passwordChecker) { warning("Cannot perform authentication, no password checker"); sendPacket(QXmppSaslFailure("temporary-auth-failure")); disconnectFromHost(); return; } if (nodeRecv.tagName() == QLatin1String("auth")) { QXmppSaslAuth auth; auth.parse(nodeRecv); d->saslServer = QXmppSaslServer::create(auth.mechanism(), this); if (!d->saslServer) { sendPacket(QXmppSaslFailure("invalid-mechanism")); disconnectFromHost(); return; } d->saslServer->setRealm(d->domain.toUtf8()); QByteArray challenge; QXmppSaslServer::Response result = d->saslServer->respond(auth.value(), challenge); if (result == QXmppSaslServer::InputNeeded) { // check credentials d->checkCredentials(auth.value()); } else if (result == QXmppSaslServer::Challenge) { sendPacket(QXmppSaslChallenge(challenge)); } else { // FIXME: what condition? sendPacket(QXmppSaslFailure()); disconnectFromHost(); return; } } else if (nodeRecv.tagName() == QLatin1String("response")) { QXmppSaslResponse response; response.parse(nodeRecv); if (!d->saslServer) { warning("SASL response received, but no mechanism selected"); sendPacket(QXmppSaslFailure()); disconnectFromHost(); return; } QByteArray challenge; QXmppSaslServer::Response result = d->saslServer->respond(response.value(), challenge); if (result == QXmppSaslServer::InputNeeded) { // check credentials d->checkCredentials(response.value()); } else if (result == QXmppSaslServer::Succeeded) { // authentication succeeded d->jid = QString("%1@%2").arg(d->saslServer->username(), d->domain); info(QString("Authentication succeeded for '%1' from %2").arg(d->jid, d->origin())); updateCounter("incoming-client.auth.success"); sendPacket(QXmppSaslSuccess()); handleStart(); } else { // FIXME: what condition? sendPacket(QXmppSaslFailure()); disconnectFromHost(); } } } else if (ns == ns_client) { if (nodeRecv.tagName() == QLatin1String("iq")) { const QString type = nodeRecv.attribute("type"); if (QXmppBindIq::isBindIq(nodeRecv) && type == QLatin1String("set")) { QXmppBindIq bindSet; bindSet.parse(nodeRecv); d->resource = bindSet.resource().trimmed(); if (d->resource.isEmpty()) d->resource = QXmppUtils::generateStanzaHash(); d->jid = QString("%1/%2").arg(QXmppUtils::jidToBareJid(d->jid), d->resource); QXmppBindIq bindResult; bindResult.setType(QXmppIq::Result); bindResult.setId(bindSet.id()); bindResult.setJid(d->jid); sendPacket(bindResult); // bound emit connected(); return; } else if (QXmppSessionIq::isSessionIq(nodeRecv) && type == QLatin1String("set")) { QXmppSessionIq sessionSet; sessionSet.parse(nodeRecv); QXmppIq sessionResult; sessionResult.setType(QXmppIq::Result); sessionResult.setId(sessionSet.id()); sessionResult.setTo(d->jid); sendPacket(sessionResult); return; } } // check the sender is legitimate const QString from = nodeRecv.attribute("from"); if (!from.isEmpty() && from != d->jid && from != QXmppUtils::jidToBareJid(d->jid)) { warning(QString("Received a stanza from unexpected JID %1").arg(from)); return; } // process unhandled stanzas if (nodeRecv.tagName() == QLatin1String("iq") || nodeRecv.tagName() == QLatin1String("message") || nodeRecv.tagName() == QLatin1String("presence")) { QDomElement nodeFull(nodeRecv); // if the sender is empty, set it to the appropriate JID if (nodeFull.attribute("from").isEmpty()) { if (nodeFull.tagName() == QLatin1String("presence") && (nodeFull.attribute("type") == QLatin1String("subscribe") || nodeFull.attribute("type") == QLatin1String("subscribed"))) nodeFull.setAttribute("from", QXmppUtils::jidToBareJid(d->jid)); else nodeFull.setAttribute("from", d->jid); } // if the recipient is empty, set it to the local domain if (nodeFull.attribute("to").isEmpty()) nodeFull.setAttribute("to", d->domain); // emit stanza for processing by server emit elementReceived(nodeFull); } } } /// \endcond void QXmppIncomingClient::onDigestReply() { QXmppPasswordReply *reply = qobject_cast(sender()); if (!reply) return; reply->deleteLater(); if (reply->error() == QXmppPasswordReply::TemporaryError) { warning(QString("Temporary authentication failure for '%1' from %2").arg(d->saslServer->username(), d->origin())); updateCounter("incoming-client.auth.temporary-auth-failure"); sendPacket(QXmppSaslFailure("temporary-auth-failure")); disconnectFromHost(); return; } QByteArray challenge; d->saslServer->setPasswordDigest(reply->digest()); QXmppSaslServer::Response result = d->saslServer->respond(reply->property("__sasl_raw").toByteArray(), challenge); if (result != QXmppSaslServer::Challenge) { warning(QString("Authentication failed for '%1' from %2").arg(d->saslServer->username(), d->origin())); updateCounter("incoming-client.auth.not-authorized"); sendPacket(QXmppSaslFailure("not-authorized")); disconnectFromHost(); return; } // send new challenge sendPacket(QXmppSaslChallenge(challenge)); } void QXmppIncomingClient::onPasswordReply() { QXmppPasswordReply *reply = qobject_cast(sender()); if (!reply) return; reply->deleteLater(); const QString jid = QString("%1@%2").arg(d->saslServer->username(), d->domain); switch (reply->error()) { case QXmppPasswordReply::NoError: d->jid = jid; info(QString("Authentication succeeded for '%1' from %2").arg(d->jid, d->origin())); updateCounter("incoming-client.auth.success"); sendPacket(QXmppSaslSuccess()); handleStart(); break; case QXmppPasswordReply::AuthorizationError: warning(QString("Authentication failed for '%1' from %2").arg(jid, d->origin())); updateCounter("incoming-client.auth.not-authorized"); sendPacket(QXmppSaslFailure("not-authorized")); disconnectFromHost(); break; case QXmppPasswordReply::TemporaryError: warning(QString("Temporary authentication failure for '%1' from %2").arg(jid, d->origin())); updateCounter("incoming-client.auth.temporary-auth-failure"); sendPacket(QXmppSaslFailure("temporary-auth-failure")); disconnectFromHost(); break; } } void QXmppIncomingClient::onSocketDisconnected() { info(QString("Socket disconnected for '%1' from %2").arg(d->jid, d->origin())); emit disconnected(); } void QXmppIncomingClient::onTimeout() { warning(QString("Idle timeout for '%1' from %2").arg(d->jid, d->origin())); disconnectFromHost(); // make sure disconnected() gets emitted no matter what QTimer::singleShot(30, this, SIGNAL(disconnected())); } qxmpp-0.9.3/src/server/QXmppIncomingClient.h000066400000000000000000000035671263006255200210420ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPINCOMINGCLIENT_H #define QXMPPINCOMINGCLIENT_H #include "QXmppStream.h" class QXmppIncomingClientPrivate; class QXmppPasswordChecker; /// \brief Interface for password checkers. /// /// \brief The QXmppIncomingClient class represents an incoming XMPP stream /// from an XMPP client. /// class QXMPP_EXPORT QXmppIncomingClient : public QXmppStream { Q_OBJECT public: QXmppIncomingClient(QSslSocket *socket, const QString &domain, QObject *parent = 0); ~QXmppIncomingClient(); bool isConnected() const; QString jid() const; void setInactivityTimeout(int secs); void setPasswordChecker(QXmppPasswordChecker *checker); signals: /// This signal is emitted when an element is received. void elementReceived(const QDomElement &element); protected: /// \cond void handleStream(const QDomElement &element); void handleStanza(const QDomElement &element); /// \endcond private slots: void onDigestReply(); void onPasswordReply(); void onSocketDisconnected(); void onTimeout(); private: Q_DISABLE_COPY(QXmppIncomingClient) QXmppIncomingClientPrivate* d; friend class QXmppIncomingClientPrivate; }; #endif qxmpp-0.9.3/src/server/QXmppIncomingServer.cpp000066400000000000000000000160431263006255200214160ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppConstants.h" #include "QXmppDialback.h" #include "QXmppIncomingServer.h" #include "QXmppOutgoingServer.h" #include "QXmppStreamFeatures.h" #include "QXmppUtils.h" class QXmppIncomingServerPrivate { public: QXmppIncomingServerPrivate(QXmppIncomingServer *qq); QString origin() const; QSet authenticated; QString domain; QString localStreamId; private: QXmppIncomingServer *q; }; QXmppIncomingServerPrivate::QXmppIncomingServerPrivate(QXmppIncomingServer *qq) : q(qq) { } QString QXmppIncomingServerPrivate::origin() const { QSslSocket *socket = q->socket(); if (socket) return socket->peerAddress().toString() + " " + QString::number(socket->peerPort()); else return ""; } /// Constructs a new incoming server stream. /// /// \param socket The socket for the XMPP stream. /// \param domain The local domain. /// \param parent The parent QObject for the stream (optional). /// QXmppIncomingServer::QXmppIncomingServer(QSslSocket *socket, const QString &domain, QObject *parent) : QXmppStream(parent) { bool check; Q_UNUSED(check); d = new QXmppIncomingServerPrivate(this); d->domain = domain; if (socket) { check = connect(socket, SIGNAL(disconnected()), this, SLOT(slotSocketDisconnected())); Q_ASSERT(check); setSocket(socket); } info(QString("Incoming server connection from %1").arg(d->origin())); } /// Destroys the current stream. QXmppIncomingServer::~QXmppIncomingServer() { delete d; } /// Returns the stream's identifier. /// QString QXmppIncomingServer::localStreamId() const { return d->localStreamId; } /// \cond void QXmppIncomingServer::handleStream(const QDomElement &streamElement) { const QString from = streamElement.attribute("from"); if (!from.isEmpty()) info(QString("Incoming server stream from %1 on %2").arg(from, d->origin())); // start stream d->localStreamId = QXmppUtils::generateStanzaHash().toLatin1(); QString data = QString("").arg( ns_server, ns_server_dialback, ns_stream, d->localStreamId); sendData(data.toUtf8()); // send stream features QXmppStreamFeatures features; if (!socket()->isEncrypted() && !socket()->localCertificate().isNull() && !socket()->privateKey().isNull()) features.setTlsMode(QXmppStreamFeatures::Enabled); sendPacket(features); } void QXmppIncomingServer::handleStanza(const QDomElement &stanza) { const QString ns = stanza.namespaceURI(); if (ns == ns_tls && stanza.tagName() == QLatin1String("starttls")) { sendData(""); socket()->flush(); socket()->startServerEncryption(); return; } else if (QXmppDialback::isDialback(stanza)) { QXmppDialback request; request.parse(stanza); // check the request is valid if (!request.type().isEmpty() || request.from().isEmpty() || request.to() != d->domain || request.key().isEmpty()) { warning(QString("Invalid dialback received on %1").arg(d->origin())); return; } const QString domain = request.from(); if (request.command() == QXmppDialback::Result) { debug(QString("Received a dialback result from '%1' on %2").arg(domain, d->origin())); // establish dialback connection QXmppOutgoingServer *stream = new QXmppOutgoingServer(d->domain, this); bool check = connect(stream, SIGNAL(dialbackResponseReceived(QXmppDialback)), this, SLOT(slotDialbackResponseReceived(QXmppDialback))); Q_ASSERT(check); Q_UNUSED(check); stream->setVerify(d->localStreamId, request.key()); stream->connectToHost(domain); } else if (request.command() == QXmppDialback::Verify) { debug(QString("Received a dialback verify from '%1' on %2").arg(domain, d->origin())); emit dialbackRequestReceived(request); } } else if (d->authenticated.contains(QXmppUtils::jidToDomain(stanza.attribute("from")))) { // relay stanza if the remote party is authenticated emit elementReceived(stanza); } else { warning(QString("Received an element from unverified domain '%1' on %2").arg(QXmppUtils::jidToDomain(stanza.attribute("from")), d->origin())); disconnectFromHost(); } } /// \endcond /// Returns true if the socket is connected and the remote server is /// authenticated. /// bool QXmppIncomingServer::isConnected() const { return QXmppStream::isConnected() && !d->authenticated.isEmpty(); } /// Handles a dialback response received from the authority server. /// /// \param response /// void QXmppIncomingServer::slotDialbackResponseReceived(const QXmppDialback &dialback) { QXmppOutgoingServer *stream = qobject_cast(sender()); if (!stream || dialback.command() != QXmppDialback::Verify || dialback.id() != d->localStreamId || dialback.from() != stream->remoteDomain()) return; // relay verify response QXmppDialback response; response.setCommand(QXmppDialback::Result); response.setTo(dialback.from()); response.setFrom(d->domain); response.setType(dialback.type()); sendPacket(response); // check for success if (response.type() == QLatin1String("valid")) { info(QString("Verified incoming domain '%1' on %2").arg(dialback.from(), d->origin())); const bool wasConnected = !d->authenticated.isEmpty(); d->authenticated.insert(dialback.from()); if (!wasConnected) emit connected(); } else { warning(QString("Failed to verify incoming domain '%1' on %2").arg(dialback.from(), d->origin())); disconnectFromHost(); } // disconnect dialback stream->disconnectFromHost(); stream->deleteLater(); } void QXmppIncomingServer::slotSocketDisconnected() { info(QString("Socket disconnected from %1").arg(d->origin())); emit disconnected(); } qxmpp-0.9.3/src/server/QXmppIncomingServer.h000066400000000000000000000036151263006255200210640ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPINCOMINGSERVER_H #define QXMPPINCOMINGSERVER_H #include "QXmppStream.h" class QXmppDialback; class QXmppIncomingServerPrivate; class QXmppOutgoingServer; /// \brief The QXmppIncomingServer class represents an incoming XMPP stream /// from an XMPP server. /// class QXMPP_EXPORT QXmppIncomingServer : public QXmppStream { Q_OBJECT public: QXmppIncomingServer(QSslSocket *socket, const QString &domain, QObject *parent); ~QXmppIncomingServer(); bool isConnected() const; QString localStreamId() const; signals: /// This signal is emitted when a dialback verify request is received. void dialbackRequestReceived(const QXmppDialback &result); /// This signal is emitted when an element is received. void elementReceived(const QDomElement &element); protected: /// \cond void handleStanza(const QDomElement &stanzaElement); void handleStream(const QDomElement &streamElement); /// \endcond private slots: void slotDialbackResponseReceived(const QXmppDialback &dialback); void slotSocketDisconnected(); private: Q_DISABLE_COPY(QXmppIncomingServer) QXmppIncomingServerPrivate* d; friend class QXmppIncomingServerPrivate; }; #endif qxmpp-0.9.3/src/server/QXmppOutgoingServer.cpp000066400000000000000000000222071263006255200214450ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #else #include "qdnslookup.h" #endif #include "QXmppConstants.h" #include "QXmppDialback.h" #include "QXmppOutgoingServer.h" #include "QXmppStreamFeatures.h" #include "QXmppUtils.h" class QXmppOutgoingServerPrivate { public: QList dataQueue; QDnsLookup dns; QString localDomain; QString localStreamKey; QString remoteDomain; QString verifyId; QString verifyKey; QTimer *dialbackTimer; bool ready; }; /// Constructs a new outgoing server-to-server stream. /// /// \param domain the local domain /// \param parent the parent object /// QXmppOutgoingServer::QXmppOutgoingServer(const QString &domain, QObject *parent) : QXmppStream(parent), d(new QXmppOutgoingServerPrivate) { bool check; Q_UNUSED(check); // socket initialisation QSslSocket *socket = new QSslSocket(this); setSocket(socket); check = connect(socket, SIGNAL(disconnected()), this, SLOT(_q_socketDisconnected())); Q_ASSERT(check); check = connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); Q_ASSERT(check); // DNS lookups check = connect(&d->dns, SIGNAL(finished()), this, SLOT(_q_dnsLookupFinished())); Q_ASSERT(check); d->dialbackTimer = new QTimer(this); d->dialbackTimer->setInterval(5000); d->dialbackTimer->setSingleShot(true); check = connect(d->dialbackTimer, SIGNAL(timeout()), this, SLOT(sendDialback())); Q_ASSERT(check); d->localDomain = domain; d->ready = false; check = connect(socket, SIGNAL(sslErrors(QList)), this, SLOT(slotSslErrors(QList))); Q_ASSERT(check); } /// Destroys the stream. /// QXmppOutgoingServer::~QXmppOutgoingServer() { delete d; } /// Attempts to connect to an XMPP server for the specified \a domain. /// /// \param domain void QXmppOutgoingServer::connectToHost(const QString &domain) { d->remoteDomain = domain; // lookup server for domain debug(QString("Looking up server for domain %1").arg(domain)); d->dns.setName("_xmpp-server._tcp." + domain); d->dns.setType(QDnsLookup::SRV); d->dns.lookup(); } void QXmppOutgoingServer::_q_dnsLookupFinished() { QString host; quint16 port; if (d->dns.error() == QDnsLookup::NoError && !d->dns.serviceRecords().isEmpty()) { // take the first returned record host = d->dns.serviceRecords().first().target(); port = d->dns.serviceRecords().first().port(); } else { // as a fallback, use domain as the host name warning(QString("Lookup for domain %1 failed: %2") .arg(d->dns.name(), d->dns.errorString())); host = d->remoteDomain; port = 5269; } #if (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) // set the name the SSL certificate should match socket()->setPeerVerifyName(d->remoteDomain); #endif // connect to server info(QString("Connecting to %1:%2").arg(host, QString::number(port))); socket()->connectToHost(host, port); } void QXmppOutgoingServer::_q_socketDisconnected() { debug("Socket disconnected"); emit disconnected(); } /// \cond void QXmppOutgoingServer::handleStart() { QXmppStream::handleStart(); QString data = QString("").arg( ns_server, ns_server_dialback, ns_stream); sendData(data.toUtf8()); } void QXmppOutgoingServer::handleStream(const QDomElement &streamElement) { Q_UNUSED(streamElement); // gmail.com servers are broken: they never send , // so we schedule sending the dialback in a couple of seconds d->dialbackTimer->start(); } void QXmppOutgoingServer::handleStanza(const QDomElement &stanza) { const QString ns = stanza.namespaceURI(); if(QXmppStreamFeatures::isStreamFeatures(stanza)) { QXmppStreamFeatures features; features.parse(stanza); if (!socket()->isEncrypted()) { // check we can satisfy TLS constraints if (!socket()->supportsSsl() && features.tlsMode() == QXmppStreamFeatures::Required) { warning("Disconnecting as TLS is required, but SSL support is not available"); disconnectFromHost(); return; } // enable TLS if possible if (socket()->supportsSsl() && features.tlsMode() != QXmppStreamFeatures::Disabled) { sendData(""); return; } } // send dialback if needed d->dialbackTimer->stop(); sendDialback(); } else if (ns == ns_tls) { if (stanza.tagName() == QLatin1String("proceed")) { debug("Starting encryption"); socket()->startClientEncryption(); return; } } else if (QXmppDialback::isDialback(stanza)) { QXmppDialback response; response.parse(stanza); // check the request is valid if (response.from().isEmpty() || response.to() != d->localDomain || response.type().isEmpty()) { warning("Invalid dialback response received"); return; } if (response.command() == QXmppDialback::Result) { if (response.type() == QLatin1String("valid")) { info(QString("Outgoing server stream to %1 is ready").arg(response.from())); d->ready = true; // send queued data foreach (const QByteArray &data, d->dataQueue) sendData(data); d->dataQueue.clear(); // emit signal emit connected(); } } else if (response.command() == QXmppDialback::Verify) { emit dialbackResponseReceived(response); } } } /// \endcond /// Returns true if the socket is connected and authentication succeeded. /// bool QXmppOutgoingServer::isConnected() const { return QXmppStream::isConnected() && d->ready; } /// Returns the stream's local dialback key. QString QXmppOutgoingServer::localStreamKey() const { return d->localStreamKey; } /// Sets the stream's local dialback key. /// /// \param key void QXmppOutgoingServer::setLocalStreamKey(const QString &key) { d->localStreamKey = key; } /// Sets the stream's verification information. /// /// \param id /// \param key void QXmppOutgoingServer::setVerify(const QString &id, const QString &key) { d->verifyId = id; d->verifyKey = key; } /// Sends or queues data until connected. /// /// \param data void QXmppOutgoingServer::queueData(const QByteArray &data) { if (isConnected()) sendData(data); else d->dataQueue.append(data); } /// Returns the remote server's domain. QString QXmppOutgoingServer::remoteDomain() const { return d->remoteDomain; } void QXmppOutgoingServer::sendDialback() { if (!d->localStreamKey.isEmpty()) { // send dialback key debug(QString("Sending dialback result to %1").arg(d->remoteDomain)); QXmppDialback dialback; dialback.setCommand(QXmppDialback::Result); dialback.setFrom(d->localDomain); dialback.setTo(d->remoteDomain); dialback.setKey(d->localStreamKey); sendPacket(dialback); } else if (!d->verifyId.isEmpty() && !d->verifyKey.isEmpty()) { // send dialback verify debug(QString("Sending dialback verify to %1").arg(d->remoteDomain)); QXmppDialback verify; verify.setCommand(QXmppDialback::Verify); verify.setId(d->verifyId); verify.setFrom(d->localDomain); verify.setTo(d->remoteDomain); verify.setKey(d->verifyKey); sendPacket(verify); } } void QXmppOutgoingServer::slotSslErrors(const QList &errors) { warning("SSL errors"); for(int i = 0; i < errors.count(); ++i) warning(errors.at(i).errorString()); socket()->ignoreSslErrors(); } void QXmppOutgoingServer::socketError(QAbstractSocket::SocketError error) { Q_UNUSED(error); emit disconnected(); } qxmpp-0.9.3/src/server/QXmppOutgoingServer.h000066400000000000000000000042121263006255200211060ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPOUTGOINGSERVER_H #define QXMPPOUTGOINGSERVER_H #include #include "QXmppStream.h" class QSslError; class QXmppDialback; class QXmppOutgoingServer; class QXmppOutgoingServerPrivate; /// \brief The QXmppOutgoingServer class represents an outgoing XMPP stream /// to another XMPP server. /// class QXMPP_EXPORT QXmppOutgoingServer : public QXmppStream { Q_OBJECT public: QXmppOutgoingServer(const QString &domain, QObject *parent); ~QXmppOutgoingServer(); bool isConnected() const; QString localStreamKey() const; void setLocalStreamKey(const QString &key); void setVerify(const QString &id, const QString &key); QString remoteDomain() const; signals: /// This signal is emitted when a dialback verify response is received. void dialbackResponseReceived(const QXmppDialback &response); protected: /// \cond void handleStart(); void handleStream(const QDomElement &streamElement); void handleStanza(const QDomElement &stanzaElement); /// \endcond public slots: void connectToHost(const QString &domain); void queueData(const QByteArray &data); private slots: void _q_dnsLookupFinished(); void _q_socketDisconnected(); void sendDialback(); void slotSslErrors(const QList &errors); void socketError(QAbstractSocket::SocketError error); private: Q_DISABLE_COPY(QXmppOutgoingServer) QXmppOutgoingServerPrivate* const d; }; #endif qxmpp-0.9.3/src/server/QXmppPasswordChecker.cpp000066400000000000000000000116211263006255200215500ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppPasswordChecker.h" /// Returns the requested domain. QString QXmppPasswordRequest::domain() const { return m_domain; } /// Sets the requested \a domain. /// /// \param domain void QXmppPasswordRequest::setDomain(const QString &domain) { m_domain = domain; } /// Returns the given password. QString QXmppPasswordRequest::password() const { return m_password; } /// Sets the given \a password. void QXmppPasswordRequest::setPassword(const QString &password) { m_password = password; } /// Returns the requested username. QString QXmppPasswordRequest::username() const { return m_username; } /// Sets the requested \a username. /// /// \param username void QXmppPasswordRequest::setUsername(const QString &username) { m_username = username; } /// Constructs a new QXmppPasswordReply. /// /// \param parent QXmppPasswordReply::QXmppPasswordReply(QObject *parent) : QObject(parent), m_error(QXmppPasswordReply::NoError), m_isFinished(false) { } /// Returns the received MD5 digest. QByteArray QXmppPasswordReply::digest() const { return m_digest; } /// Sets the received MD5 digest. /// /// \param digest void QXmppPasswordReply::setDigest(const QByteArray &digest) { m_digest = digest; } /// Returns the error that was found during the processing of this request. /// /// If no error was found, returns NoError. QXmppPasswordReply::Error QXmppPasswordReply::error() const { return m_error; } /// Returns the error that was found during the processing of this request. /// void QXmppPasswordReply::setError(QXmppPasswordReply::Error error) { m_error = error; } /// Mark reply as finished. void QXmppPasswordReply::finish() { m_isFinished = true; emit finished(); } /// Delay marking reply as finished. void QXmppPasswordReply::finishLater() { QTimer::singleShot(0, this, SLOT(finish())); } /// Returns true when the reply has finished. bool QXmppPasswordReply::isFinished() const { return m_isFinished; } /// Returns the received password. QString QXmppPasswordReply::password() const { return m_password; } /// Sets the received password. /// /// \param password void QXmppPasswordReply::setPassword(const QString &password) { m_password = password; } /// Checks that the given credentials are valid. /// /// The base implementation requires that you reimplement getPassword(). /// /// \param request QXmppPasswordReply *QXmppPasswordChecker::checkPassword(const QXmppPasswordRequest &request) { QXmppPasswordReply *reply = new QXmppPasswordReply; QString secret; QXmppPasswordReply::Error error = getPassword(request, secret); if (error == QXmppPasswordReply::NoError) { if (request.password() != secret) reply->setError(QXmppPasswordReply::AuthorizationError); } else { reply->setError(error); } // reply is finished reply->finishLater(); return reply; } /// Retrieves the MD5 digest for the given username. /// /// Reimplement this method if your backend natively supports /// retrieving MD5 digests. /// /// \param request QXmppPasswordReply *QXmppPasswordChecker::getDigest(const QXmppPasswordRequest &request) { QXmppPasswordReply *reply = new QXmppPasswordReply; QString secret; QXmppPasswordReply::Error error = getPassword(request, secret); if (error == QXmppPasswordReply::NoError) { reply->setDigest(QCryptographicHash::hash( (request.username() + ":" + request.domain() + ":" + secret).toUtf8(), QCryptographicHash::Md5)); } else { reply->setError(error); } // reply is finished reply->finishLater(); return reply; } /// Retrieves the password for the given username. /// /// The simplest way to write a password checker is to reimplement this method. /// /// \param request /// \param password QXmppPasswordReply::Error QXmppPasswordChecker::getPassword(const QXmppPasswordRequest &request, QString &password) { Q_UNUSED(request); Q_UNUSED(password); return QXmppPasswordReply::TemporaryError; } /// Returns true if the getPassword() method is implemented. /// bool QXmppPasswordChecker::hasGetPassword() const { return false; } qxmpp-0.9.3/src/server/QXmppPasswordChecker.h000066400000000000000000000052741263006255200212240ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPPASSWORDCHECKER_H #define QXMPPPASSWORDCHECKER_H #include #include "QXmppGlobal.h" /// \brief The QXmppPasswordRequest class represents a password request. /// class QXMPP_EXPORT QXmppPasswordRequest { public: /// This enum is used to describe request types. enum Type { CheckPassword = 0 }; QString domain() const; void setDomain(const QString &domain); QString password() const; void setPassword(const QString &password); QString username() const; void setUsername(const QString &username); private: QString m_domain; QString m_password; QString m_username; }; /// \brief The QXmppPasswordReply class represents a password reply. /// class QXMPP_EXPORT QXmppPasswordReply : public QObject { Q_OBJECT public: /// This enum is used to describe authentication errors. enum Error { NoError = 0, AuthorizationError, TemporaryError }; QXmppPasswordReply(QObject *parent = 0); QByteArray digest() const; void setDigest(const QByteArray &digest); QString password() const; void setPassword(const QString &password); QXmppPasswordReply::Error error() const; void setError(QXmppPasswordReply::Error error); bool isFinished() const; public slots: void finish(); void finishLater(); signals: /// This signal is emitted when the reply has finished. void finished(); private: QByteArray m_digest; QString m_password; QXmppPasswordReply::Error m_error; bool m_isFinished; }; /// \brief The QXmppPasswordChecker class represents an abstract password checker. /// class QXMPP_EXPORT QXmppPasswordChecker { public: virtual QXmppPasswordReply *checkPassword(const QXmppPasswordRequest &request); virtual QXmppPasswordReply *getDigest(const QXmppPasswordRequest &request); virtual bool hasGetPassword() const; protected: virtual QXmppPasswordReply::Error getPassword(const QXmppPasswordRequest &request, QString &password); }; #endif qxmpp-0.9.3/src/server/QXmppServer.cpp000066400000000000000000000634551263006255200177430ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppConstants.h" #include "QXmppDialback.h" #include "QXmppIq.h" #include "QXmppIncomingClient.h" #include "QXmppIncomingServer.h" #include "QXmppOutgoingServer.h" #include "QXmppPresence.h" #include "QXmppServer.h" #include "QXmppServerExtension.h" #include "QXmppServerPlugin.h" #include "QXmppUtils.h" static 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(); } class QXmppServerPrivate { public: QXmppServerPrivate(QXmppServer *qq); void loadExtensions(QXmppServer *server); bool routeData(const QString &to, const QByteArray &data); void startExtensions(); void stopExtensions(); void info(const QString &message); void warning(const QString &message); QString domain; QList extensions; QXmppLogger *logger; QXmppPasswordChecker *passwordChecker; // client-to-server QSet incomingClients; QHash incomingClientsByJid; QHash > incomingClientsByBareJid; QSet serversForClients; // server-to-server QSet incomingServers; QSet outgoingServers; QSet serversForServers; // ssl QList caCertificates; QSslCertificate localCertificate; QSslKey privateKey; private: bool loaded; bool started; QXmppServer *q; }; QXmppServerPrivate::QXmppServerPrivate(QXmppServer *qq) : logger(0), passwordChecker(0), loaded(false), started(false), q(qq) { } /// Routes XMPP data to the given recipient. /// /// \param to /// \param data /// bool QXmppServerPrivate::routeData(const QString &to, const QByteArray &data) { // refuse to route packets to empty destination, own domain or sub-domains const QString toDomain = QXmppUtils::jidToDomain(to); if (to.isEmpty() || to == domain || toDomain.endsWith("." + domain)) return false; if (toDomain == domain) { // look for a client connection QList found; if (QXmppUtils::jidToResource(to).isEmpty()) { foreach (QXmppIncomingClient *conn, incomingClientsByBareJid.value(to)) found << conn; } else { QXmppIncomingClient *conn = incomingClientsByJid.value(to); if (conn) found << conn; } // send data foreach (QXmppStream *conn, found) QMetaObject::invokeMethod(conn, "sendData", Q_ARG(QByteArray, data)); return !found.isEmpty(); } else if (!serversForServers.isEmpty()) { bool check; Q_UNUSED(check); // look for an outgoing S2S connection foreach (QXmppOutgoingServer *conn, outgoingServers) { if (conn->remoteDomain() == toDomain) { // send or queue data QMetaObject::invokeMethod(conn, "queueData", Q_ARG(QByteArray, data)); return true; } } // if we did not find an outgoing server, // we need to establish the S2S connection QXmppOutgoingServer *conn = new QXmppOutgoingServer(domain, 0); conn->setLocalStreamKey(QXmppUtils::generateStanzaHash().toLatin1()); conn->moveToThread(q->thread()); conn->setParent(q); check = QObject::connect(conn, SIGNAL(disconnected()), q, SLOT(_q_outgoingServerDisconnected())); Q_UNUSED(check); // add stream outgoingServers.insert(conn); q->setGauge("outgoing-server.count", outgoingServers.size()); // queue data and connect to remote server QMetaObject::invokeMethod(conn, "queueData", Q_ARG(QByteArray, data)); QMetaObject::invokeMethod(conn, "connectToHost", Q_ARG(QString, toDomain)); return true; } else { // S2S is disabled, failed to route data return false; } } /// Handles an incoming XML element. /// /// \param server /// \param stream /// \param element static void handleStanza(QXmppServer *server, const QDomElement &element) { // try extensions foreach (QXmppServerExtension *extension, server->extensions()) if (extension->handleStanza(element)) return; // default handlers const QString domain = server->domain(); const QString to = element.attribute("to"); if (to == domain) { if (element.tagName() == QLatin1String("iq")) { // we do not support the given IQ QXmppIq request; request.parse(element); if (request.type() != QXmppIq::Error && request.type() != QXmppIq::Result) { QXmppIq response(QXmppIq::Error); response.setId(request.id()); response.setFrom(domain); response.setTo(request.from()); QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::FeatureNotImplemented); response.setError(error); server->sendPacket(response); } } } else { // route element or reply on behalf of missing peer if (!server->sendElement(element) && element.tagName() == QLatin1String("iq")) { QXmppIq request; request.parse(element); QXmppIq response(QXmppIq::Error); response.setId(request.id()); response.setFrom(request.to()); response.setTo(request.from()); QXmppStanza::Error error(QXmppStanza::Error::Cancel, QXmppStanza::Error::ServiceUnavailable); response.setError(error); server->sendPacket(response); } } } void QXmppServerPrivate::info(const QString &message) { if (logger) logger->log(QXmppLogger::InformationMessage, message); } void QXmppServerPrivate::warning(const QString &message) { if (logger) logger->log(QXmppLogger::WarningMessage, message); } /// Load the server's extensions. /// /// \param server void QXmppServerPrivate::loadExtensions(QXmppServer *server) { if (!loaded) { QObjectList plugins = QPluginLoader::staticInstances(); foreach (QObject *object, plugins) { QXmppServerPlugin *plugin = qobject_cast(object); if (!plugin) continue; foreach (const QString &key, plugin->keys()) server->addExtension(plugin->create(key)); } loaded = true; } } /// Start the server's extensions. void QXmppServerPrivate::startExtensions() { if (!started) { foreach (QXmppServerExtension *extension, extensions) if (!extension->start()) warning(QString("Could not start extension %1").arg(extension->extensionName())); started = true; } } /// Stop the server's extensions (in reverse order). /// void QXmppServerPrivate::stopExtensions() { if (started) { for (int i = extensions.size() - 1; i >= 0; --i) extensions[i]->stop(); started = false; } } /// Constructs a new XMPP server instance. /// /// \param parent QXmppServer::QXmppServer(QObject *parent) : QXmppLoggable(parent) , d(new QXmppServerPrivate(this)) { qRegisterMetaType("QDomElement"); } /// Destroys an XMPP server instance. /// QXmppServer::~QXmppServer() { close(); delete d; } /// Registers a new extension with the server. /// /// \param extension void QXmppServer::addExtension(QXmppServerExtension *extension) { if (!extension || d->extensions.contains(extension)) return; d->info(QString("Added extension %1").arg(extension->extensionName())); extension->setParent(this); extension->setServer(this); // keep extensions sorted by priority for (int i = 0; i < d->extensions.size(); ++i) { QXmppServerExtension *other = d->extensions[i]; if (other->extensionPriority() < extension->extensionPriority()) { d->extensions.insert(i, extension); return; } } d->extensions << extension; } /// Returns the list of loaded extensions. /// QList QXmppServer::extensions() { d->loadExtensions(this); return d->extensions; } /// Returns the server's domain. /// QString QXmppServer::domain() const { return d->domain; } /// Sets the server's domain. /// /// \param domain void QXmppServer::setDomain(const QString &domain) { d->domain = domain; } /// Returns the QXmppLogger associated with the server. /// QXmppLogger *QXmppServer::logger() { return d->logger; } /// Sets the QXmppLogger associated with the server. /// /// \param logger void QXmppServer::setLogger(QXmppLogger *logger) { if (logger != d->logger) { if (d->logger) { disconnect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), d->logger, SLOT(log(QXmppLogger::MessageType,QString))); disconnect(this, SIGNAL(setGauge(QString,double)), d->logger, SLOT(setGauge(QString,double))); disconnect(this, SIGNAL(updateCounter(QString,qint64)), d->logger, SLOT(updateCounter(QString,qint64))); } d->logger = logger; if (d->logger) { connect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), d->logger, SLOT(log(QXmppLogger::MessageType,QString))); connect(this, SIGNAL(setGauge(QString,double)), d->logger, SLOT(setGauge(QString,double))); connect(this, SIGNAL(updateCounter(QString,qint64)), d->logger, SLOT(updateCounter(QString,qint64))); } emit loggerChanged(d->logger); } } /// Returns the password checker used to verify client credentials. /// QXmppPasswordChecker *QXmppServer::passwordChecker() { return d->passwordChecker; } /// Sets the password checker used to verify client credentials. /// /// \param checker /// void QXmppServer::setPasswordChecker(QXmppPasswordChecker *checker) { d->passwordChecker = checker; } /// Returns the statistics for the server. QVariantMap QXmppServer::statistics() const { QVariantMap stats; stats["version"] = qApp->applicationVersion(); stats["incoming-clients"] = d->incomingClients.size(); stats["incoming-servers"] = d->incomingServers.size(); stats["outgoing-servers"] = d->outgoingServers.size(); return stats; } /// Sets the path for additional SSL CA certificates. /// /// \param path void QXmppServer::addCaCertificates(const QString &path) { // load certificates if (path.isEmpty()) { d->caCertificates = QList(); } else if (QFileInfo(path).isReadable()) { d->caCertificates = QSslCertificate::fromPath(path); } else { d->warning(QString("SSL CA certificates are not readable %1").arg(path)); d->caCertificates = QList(); } // reconfigure servers foreach (QXmppSslServer *server, d->serversForClients + d->serversForServers) server->addCaCertificates(d->caCertificates); } /// Sets the path for the local SSL certificate. /// /// \param path void QXmppServer::setLocalCertificate(const QString &path) { // load certificate QSslCertificate certificate; QFile file(path); if (path.isEmpty()) { d->localCertificate = QSslCertificate(); } else if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { d->localCertificate = QSslCertificate(file.readAll()); } else { d->warning(QString("SSL certificate is not readable %1").arg(path)); d->localCertificate = QSslCertificate(); } // reconfigure servers foreach (QXmppSslServer *server, d->serversForClients + d->serversForServers) server->setLocalCertificate(d->localCertificate); } /// Sets the local SSL certificate /// /// \param certificate void QXmppServer::setLocalCertificate(const QSslCertificate &certificate) { d->localCertificate = certificate; // reconfigure servers foreach (QXmppSslServer *server, d->serversForClients + d->serversForServers) server->setLocalCertificate(d->localCertificate); } /// Sets the path for the local SSL private key. /// /// \param path void QXmppServer::setPrivateKey(const QString &path) { // load key QSslKey key; QFile file(path); if (path.isEmpty()) { d->privateKey = QSslKey(); } else if (file.open(QIODevice::ReadOnly)) { d->privateKey = QSslKey(file.readAll(), QSsl::Rsa); } else { d->warning(QString("SSL key is not readable %1").arg(path)); d->privateKey = QSslKey(); } // reconfigure servers foreach (QXmppSslServer *server, d->serversForClients + d->serversForServers) server->setPrivateKey(d->privateKey); } /// Sets the local SSL private key. /// /// \param key void QXmppServer::setPrivateKey(const QSslKey &key) { d->privateKey = key; // reconfigure servers foreach (QXmppSslServer *server, d->serversForClients + d->serversForServers) server->setPrivateKey(d->privateKey); } /// Listen for incoming XMPP client connections. /// /// \param address /// \param port bool QXmppServer::listenForClients(const QHostAddress &address, quint16 port) { bool check; Q_UNUSED(check); if (d->domain.isEmpty()) { d->warning("No domain was specified!"); return false; } // create new server QXmppSslServer *server = new QXmppSslServer(this); server->addCaCertificates(d->caCertificates); server->setLocalCertificate(d->localCertificate); server->setPrivateKey(d->privateKey); check = connect(server, SIGNAL(newConnection(QSslSocket*)), this, SLOT(_q_clientConnection(QSslSocket*))); Q_ASSERT(check); if (!server->listen(address, port)) { d->warning(QString("Could not start listening for C2S on %1 %2").arg(address.toString(), QString::number(port))); delete server; return false; } d->serversForClients.insert(server); // start extensions d->loadExtensions(this); d->startExtensions(); return true; } /// Closes the server. /// void QXmppServer::close() { // prevent new connections foreach (QXmppSslServer *server, d->serversForClients + d->serversForServers) { server->close(); delete server; } d->serversForClients.clear(); d->serversForServers.clear(); // stop extensions d->stopExtensions(); // close XMPP streams foreach (QXmppIncomingClient *stream, d->incomingClients) stream->disconnectFromHost(); foreach (QXmppIncomingServer *stream, d->incomingServers) stream->disconnectFromHost(); foreach (QXmppOutgoingServer *stream, d->outgoingServers) stream->disconnectFromHost(); } /// Listen for incoming XMPP server connections. /// /// \param address /// \param port bool QXmppServer::listenForServers(const QHostAddress &address, quint16 port) { bool check; Q_UNUSED(check); if (d->domain.isEmpty()) { d->warning("No domain was specified!"); return false; } // create new server QXmppSslServer *server = new QXmppSslServer(this); server->addCaCertificates(d->caCertificates); server->setLocalCertificate(d->localCertificate); server->setPrivateKey(d->privateKey); check = connect(server, SIGNAL(newConnection(QSslSocket*)), this, SLOT(_q_serverConnection(QSslSocket*))); Q_ASSERT(check); if (!server->listen(address, port)) { d->warning(QString("Could not start listening for S2S on %1 %2").arg(address.toString(), QString::number(port))); delete server; return false; } d->serversForServers.insert(server); // start extensions d->loadExtensions(this); d->startExtensions(); return true; } /// Route an XMPP stanza. /// /// \param element bool QXmppServer::sendElement(const QDomElement &element) { // serialize data QByteArray data; QXmlStreamWriter xmlStream(&data); const QStringList omitNamespaces = QStringList() << ns_client << ns_server; helperToXmlAddDomElement(&xmlStream, element, omitNamespaces); // route data return d->routeData(element.attribute("to"), data); } /// Route an XMPP packet. /// /// \param packet bool QXmppServer::sendPacket(const QXmppStanza &packet) { // serialize data QByteArray data; QXmlStreamWriter xmlStream(&data); packet.toXml(&xmlStream); // route data return d->routeData(packet.to(), data); } /// Add a new incoming client \a stream. /// /// This method can be used for instance to implement BOSH support /// as a server extension. void QXmppServer::addIncomingClient(QXmppIncomingClient *stream) { bool check; Q_UNUSED(check); stream->setPasswordChecker(d->passwordChecker); check = connect(stream, SIGNAL(connected()), this, SLOT(_q_clientConnected())); Q_ASSERT(check); check = connect(stream, SIGNAL(disconnected()), this, SLOT(_q_clientDisconnected())); Q_ASSERT(check); check = connect(stream, SIGNAL(elementReceived(QDomElement)), this, SLOT(handleElement(QDomElement))); Q_ASSERT(check); // add stream d->incomingClients.insert(stream); setGauge("incoming-client.count", d->incomingClients.size()); } /// Handle a new incoming TCP connection from a client. /// /// \param socket void QXmppServer::_q_clientConnection(QSslSocket *socket) { // check the socket didn't die since the signal was emitted if (socket->state() != QAbstractSocket::ConnectedState) { delete socket; return; } QXmppIncomingClient *stream = new QXmppIncomingClient(socket, d->domain, this); stream->setInactivityTimeout(120); socket->setParent(stream); addIncomingClient(stream); } /// Handle a successful stream connection for a client. /// void QXmppServer::_q_clientConnected() { QXmppIncomingClient *client = qobject_cast(sender()); if (!client) return; // FIXME: at this point the JID must contain a resource, assert it? const QString jid = client->jid(); // check whether the connection conflicts with another one QXmppIncomingClient *old = d->incomingClientsByJid.value(jid); if (old && old != client) { old->sendData("Replaced by new connection"); old->disconnectFromHost(); } d->incomingClientsByJid.insert(jid, client); d->incomingClientsByBareJid[QXmppUtils::jidToBareJid(jid)].insert(client); // emit signal emit clientConnected(jid); } /// Handle a stream disconnection for a client. void QXmppServer::_q_clientDisconnected() { QXmppIncomingClient *client = qobject_cast(sender()); if (!client) return; if (d->incomingClients.remove(client)) { // remove stream from routing tables const QString jid = client->jid(); if (!jid.isEmpty()) { if (d->incomingClientsByJid.value(jid) == client) d->incomingClientsByJid.remove(jid); const QString bareJid = QXmppUtils::jidToBareJid(jid); if (d->incomingClientsByBareJid.contains(bareJid)) { d->incomingClientsByBareJid[bareJid].remove(client); if (d->incomingClientsByBareJid[bareJid].isEmpty()) d->incomingClientsByBareJid.remove(bareJid); } } // destroy client client->deleteLater(); // emit signal if (!jid.isEmpty()) emit clientDisconnected(jid); // update counter setGauge("incoming-client.count", d->incomingClients.size()); } } void QXmppServer::_q_dialbackRequestReceived(const QXmppDialback &dialback) { QXmppIncomingServer *stream = qobject_cast(sender()); if (!stream) return; if (dialback.command() == QXmppDialback::Verify) { // handle a verify request foreach (QXmppOutgoingServer *out, d->outgoingServers) { if (out->remoteDomain() != dialback.from()) continue; bool isValid = dialback.key() == out->localStreamKey(); QXmppDialback verify; verify.setCommand(QXmppDialback::Verify); verify.setId(dialback.id()); verify.setTo(dialback.from()); verify.setFrom(d->domain); verify.setType(isValid ? "valid" : "invalid"); stream->sendPacket(verify); return; } } } /// Handle an incoming XML element. void QXmppServer::handleElement(const QDomElement &element) { handleStanza(this, element); } /// Handle a stream disconnection for an outgoing server. void QXmppServer::_q_outgoingServerDisconnected() { QXmppOutgoingServer *outgoing = qobject_cast(sender()); if (!outgoing) return; if (d->outgoingServers.remove(outgoing)) { outgoing->deleteLater(); setGauge("outgoing-server.count", d->outgoingServers.size()); } } /// Handle a new incoming TCP connection from a server. /// /// \param socket void QXmppServer::_q_serverConnection(QSslSocket *socket) { bool check; Q_UNUSED(check); // check the socket didn't die since the signal was emitted if (socket->state() != QAbstractSocket::ConnectedState) { delete socket; return; } QXmppIncomingServer *stream = new QXmppIncomingServer(socket, d->domain, this); socket->setParent(stream); check = connect(stream, SIGNAL(disconnected()), this, SLOT(_q_serverDisconnected())); Q_ASSERT(check); check = connect(stream, SIGNAL(dialbackRequestReceived(QXmppDialback)), this, SLOT(_q_dialbackRequestReceived(QXmppDialback))); Q_ASSERT(check); check = connect(stream, SIGNAL(elementReceived(QDomElement)), this, SLOT(handleElement(QDomElement))); Q_ASSERT(check); // add stream d->incomingServers.insert(stream); setGauge("incoming-server.count", d->incomingServers.size()); } /// Handle a stream disconnection for an incoming server. void QXmppServer::_q_serverDisconnected() { QXmppIncomingServer *incoming = qobject_cast(sender()); if (!incoming) return; if (d->incomingServers.remove(incoming)) { incoming->deleteLater(); setGauge("incoming-server.count", d->incomingServers.size()); } } class QXmppSslServerPrivate { public: QList caCertificates; QSslCertificate localCertificate; QSslKey privateKey; }; /// Constructs a new SSL server instance. /// /// \param parent QXmppSslServer::QXmppSslServer(QObject *parent) : QTcpServer(parent), d(new QXmppSslServerPrivate) { } /// Destroys an SSL server instance. /// QXmppSslServer::~QXmppSslServer() { delete d; } #if QT_VERSION < 0x050000 void QXmppSslServer::incomingConnection(int socketDescriptor) #else void QXmppSslServer::incomingConnection(qintptr socketDescriptor) #endif { QSslSocket *socket = new QSslSocket; if (!socket->setSocketDescriptor(socketDescriptor)) { delete socket; return; } if (!d->localCertificate.isNull() && !d->privateKey.isNull()) { socket->setProtocol(QSsl::AnyProtocol); socket->addCaCertificates(d->caCertificates); socket->setLocalCertificate(d->localCertificate); socket->setPrivateKey(d->privateKey); } emit newConnection(socket); } /// Adds the given certificates to the CA certificate database to be used /// for incoming connnections. /// /// \param certificates void QXmppSslServer::addCaCertificates(const QList &certificates) { d->caCertificates += certificates; } /// Sets the local certificate to be used for incoming connections. /// /// \param certificate void QXmppSslServer::setLocalCertificate(const QSslCertificate &certificate) { d->localCertificate = certificate; } /// Sets the local private key to be used for incoming connections. /// /// \param key void QXmppSslServer::setPrivateKey(const QSslKey &key) { d->privateKey = key; } qxmpp-0.9.3/src/server/QXmppServer.h000066400000000000000000000104631263006255200173770ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPSERVER_H #define QXMPPSERVER_H #include #include #include "QXmppLogger.h" class QDomElement; class QSslCertificate; class QSslKey; class QSslSocket; class QXmppDialback; class QXmppIncomingClient; class QXmppOutgoingServer; class QXmppPasswordChecker; class QXmppPresence; class QXmppServerExtension; class QXmppServerPrivate; class QXmppSslServer; class QXmppStanza; class QXmppStream; /// \brief The QXmppServer class represents an XMPP server. /// /// It provides support for both client-to-server and server-to-server /// communications, SSL encryption and logging facilities. /// /// QXmppServer comes with a number of modules for service discovery, /// XMPP ping, statistics and file transfer proxy support. You can write /// your own extensions for QXmppServer by subclassing QXmppServerExtension. /// /// \ingroup Core class QXMPP_EXPORT QXmppServer : public QXmppLoggable { Q_OBJECT Q_PROPERTY(QXmppLogger* logger READ logger WRITE setLogger NOTIFY loggerChanged) public: QXmppServer(QObject *parent = 0); ~QXmppServer(); void addExtension(QXmppServerExtension *extension); QList extensions(); QString domain() const; void setDomain(const QString &domain); QXmppLogger *logger(); void setLogger(QXmppLogger *logger); QXmppPasswordChecker *passwordChecker(); void setPasswordChecker(QXmppPasswordChecker *checker); QVariantMap statistics() const; void addCaCertificates(const QString &caCertificates); void setLocalCertificate(const QString &path); void setLocalCertificate(const QSslCertificate &certificate); void setPrivateKey(const QString &path); void setPrivateKey(const QSslKey &key); void close(); bool listenForClients(const QHostAddress &address = QHostAddress::Any, quint16 port = 5222); bool listenForServers(const QHostAddress &address = QHostAddress::Any, quint16 port = 5269); bool sendElement(const QDomElement &element); bool sendPacket(const QXmppStanza &stanza); void addIncomingClient(QXmppIncomingClient *stream); signals: /// This signal is emitted when a client has connected. void clientConnected(const QString &jid); /// This signal is emitted when a client has disconnected. void clientDisconnected(const QString &jid); /// This signal is emitted when the logger changes. void loggerChanged(QXmppLogger *logger); public slots: void handleElement(const QDomElement &element); private slots: void _q_clientConnection(QSslSocket *socket); void _q_clientConnected(); void _q_clientDisconnected(); void _q_dialbackRequestReceived(const QXmppDialback &dialback); void _q_outgoingServerDisconnected(); void _q_serverConnection(QSslSocket *socket); void _q_serverDisconnected(); private: friend class QXmppServerPrivate; QXmppServerPrivate *d; }; class QXmppSslServerPrivate; /// \brief The QXmppSslServer class represents an SSL-enabled TCP server. /// class QXMPP_EXPORT QXmppSslServer : public QTcpServer { Q_OBJECT public: QXmppSslServer(QObject *parent = 0); ~QXmppSslServer(); void addCaCertificates(const QList &certificates); void setLocalCertificate(const QSslCertificate &certificate); void setPrivateKey(const QSslKey &key); signals: /// This signal is emitted when a new connection is established. void newConnection(QSslSocket *socket); private: #if QT_VERSION < 0x050000 void incomingConnection(int socketDescriptor); #else void incomingConnection(qintptr socketDescriptor); #endif QXmppSslServerPrivate * const d; }; #endif qxmpp-0.9.3/src/server/QXmppServerExtension.cpp000066400000000000000000000061211263006255200216230ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppLogger.h" #include "QXmppServer.h" #include "QXmppServerExtension.h" class QXmppServerExtensionPrivate { public: QXmppServer *server; }; QXmppServerExtension::QXmppServerExtension() : d(new QXmppServerExtensionPrivate) { d->server = 0; } QXmppServerExtension::~QXmppServerExtension() { delete d; } /// Returns the discovery features to add to the server. /// QStringList QXmppServerExtension::discoveryFeatures() const { return QStringList(); } /// Returns the discovery items to add to the server. /// QStringList QXmppServerExtension::discoveryItems() const { return QStringList(); } /// Returns the extension's name. /// QString QXmppServerExtension::extensionName() const { int index = metaObject()->indexOfClassInfo("ExtensionName"); if (index < 0) return QString(); const char *name = metaObject()->classInfo(index).value(); return QString::fromLatin1(name); } /// Returns the extension's priority. /// /// Higher priority extensions are called first when handling /// incoming stanzas. /// /// The default implementation returns 0. int QXmppServerExtension::extensionPriority() const { return 0; } /// Handles an incoming XMPP stanza. /// /// Return true if no further processing should occur, false otherwise. /// /// \param stanza The received stanza. bool QXmppServerExtension::handleStanza(const QDomElement &stanza) { Q_UNUSED(stanza); return false; } /// Returns the list of subscribers for the given JID. /// /// \param jid QSet QXmppServerExtension::presenceSubscribers(const QString &jid) { Q_UNUSED(jid); return QSet(); } /// Returns the list of subscriptions for the given JID. /// /// \param jid QSet QXmppServerExtension::presenceSubscriptions(const QString &jid) { Q_UNUSED(jid); return QSet(); } /// Starts the extension. /// /// Return true if the extension was started, false otherwise. bool QXmppServerExtension::start() { return true; } /// Stops the extension. void QXmppServerExtension::stop() { } /// Returns the server which loaded this extension. QXmppServer *QXmppServerExtension::server() const { return d->server; } /// Sets the server which loaded this extension. /// /// \param server void QXmppServerExtension::setServer(QXmppServer *server) { d->server = server; } qxmpp-0.9.3/src/server/QXmppServerExtension.h000066400000000000000000000040501263006255200212670ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPSERVEREXTENSION_H #define QXMPPSERVEREXTENSION_H #include #include "QXmppLogger.h" class QDomElement; class QStringList; class QXmppServer; class QXmppServerExtensionPrivate; class QXmppStream; /// \brief The QXmppServerExtension class is the base class for QXmppServer /// extensions. /// /// If you want to extend QXmppServer, for instance to support an IQ type /// which is not natively supported, you can subclass QXmppServerExtension /// and implement handleStanza(). You can then add your extension to the /// client instance using QXmppServer::addExtension(). /// /// \ingroup Core class QXMPP_EXPORT QXmppServerExtension : public QXmppLoggable { Q_OBJECT public: QXmppServerExtension(); ~QXmppServerExtension(); virtual QString extensionName() const; virtual int extensionPriority() const; virtual QStringList discoveryFeatures() const; virtual QStringList discoveryItems() const; virtual bool handleStanza(const QDomElement &stanza); virtual QSet presenceSubscribers(const QString &jid); virtual QSet presenceSubscriptions(const QString &jid); virtual bool start(); virtual void stop(); protected: QXmppServer *server() const; private: void setServer(QXmppServer *server); QXmppServerExtensionPrivate * const d; friend class QXmppServer; }; #endif qxmpp-0.9.3/src/server/QXmppServerPlugin.h000066400000000000000000000033771263006255200205640ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 QXMPPSERVERPLUGIN_H #define QXMPPSERVERPLUGIN_H #include #include "QXmppGlobal.h" class QXmppServer; class QXmppServerExtension; class QXMPP_EXPORT QXmppServerPluginInterface { public: /// Creates the server extension identified by \a key. virtual QXmppServerExtension *create(const QString &key) = 0; /// Returns a list of valid extension keys. virtual QStringList keys() const = 0; }; Q_DECLARE_INTERFACE(QXmppServerPluginInterface, "com.googlecode.qxmpp.ServerPlugin/1.0") /// \brief The QXmppServerPlugin class is the base class for QXmppServer plugins. /// class QXMPP_EXPORT QXmppServerPlugin : public QObject, public QXmppServerPluginInterface { Q_OBJECT Q_INTERFACES(QXmppServerPluginInterface) public: /// Creates and returns the specified QXmppServerExtension. /// /// \param key The key for the QXmppServerExtension. virtual QXmppServerExtension *create(const QString &key) = 0; /// Returns the list of keys supported by this plugin. /// virtual QStringList keys() const = 0; }; #endif qxmpp-0.9.3/src/server/server.pri000066400000000000000000000010711263006255200170070ustar00rootroot00000000000000# Headers INSTALL_HEADERS += \ server/QXmppDialback.h \ server/QXmppIncomingClient.h \ server/QXmppIncomingServer.h \ server/QXmppOutgoingServer.h \ server/QXmppPasswordChecker.h \ server/QXmppServer.h \ server/QXmppServerExtension.h \ server/QXmppServerPlugin.h # Source files SOURCES += \ server/QXmppDialback.cpp \ server/QXmppIncomingClient.cpp \ server/QXmppIncomingServer.cpp \ server/QXmppOutgoingServer.cpp \ server/QXmppPasswordChecker.cpp \ server/QXmppServer.cpp \ server/QXmppServerExtension.cpp qxmpp-0.9.3/src/src.pro000066400000000000000000000017111263006255200147710ustar00rootroot00000000000000include(../qxmpp.pri) QT -= gui TEMPLATE = lib CONFIG += $$QXMPP_LIBRARY_TYPE DEFINES += QXMPP_BUILD DEFINES += $$QXMPP_INTERNAL_DEFINES INCLUDEPATH += $$QXMPP_INCLUDEPATH $$QXMPP_INTERNAL_INCLUDES LIBS += $$QXMPP_INTERNAL_LIBS # Target definition TARGET = $$QXMPP_LIBRARY_NAME VERSION = $$QXMPP_VERSION win32 { DESTDIR = $$OUT_PWD } include(base/base.pri) include(client/client.pri) include(server/server.pri) HEADERS += $$INSTALL_HEADERS # Installation headers.files = $$INSTALL_HEADERS headers.path = $$PREFIX/include/qxmpp target.path = $$PREFIX/$$LIBDIR INSTALLS += headers target # pkg-config support CONFIG += create_pc create_prl no_install_prl QMAKE_PKGCONFIG_DESTDIR = pkgconfig QMAKE_PKGCONFIG_LIBDIR = $$target.path QMAKE_PKGCONFIG_INCDIR = $$headers.path equals(QXMPP_LIBRARY_TYPE,staticlib) { QMAKE_PKGCONFIG_CFLAGS = -DQXMPP_STATIC } else { QMAKE_PKGCONFIG_CFLAGS = -DQXMPP_SHARED } unix:QMAKE_CLEAN += -r pkgconfig lib$${TARGET}.prl qxmpp-0.9.3/tests/000077500000000000000000000000001263006255200140335ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmpparchiveiq/000077500000000000000000000000001263006255200170745ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmpparchiveiq/qxmpparchiveiq.pro000066400000000000000000000001241263006255200226540ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmpparchiveiq SOURCES += tst_qxmpparchiveiq.cpp qxmpp-0.9.3/tests/qxmpparchiveiq/tst_qxmpparchiveiq.cpp000066400000000000000000000156111263006255200235370ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppArchiveIq.h" #include "util.h" class tst_QXmppArchiveIq : public QObject { Q_OBJECT private slots: void testArchiveList_data(); void testArchiveList(); void testArchiveChat_data(); void testArchiveChat(); void testArchiveRemove(); void testArchiveRetrieve_data(); void testArchiveRetrieve(); }; void tst_QXmppArchiveIq::testArchiveList_data() { QTest::addColumn("xml"); QTest::addColumn("max"); QTest::newRow("no rsm") << QByteArray( "" "" "") << -1; QTest::newRow("with rsm") << QByteArray( "" "" "" "30" "" "" "") << 30; } void tst_QXmppArchiveIq::testArchiveList() { QFETCH(QByteArray, xml); QFETCH(int, max); QXmppArchiveListIq iq; parsePacket(iq, xml); QCOMPARE(iq.type(), QXmppIq::Get); QCOMPARE(iq.id(), QLatin1String("list_1")); QCOMPARE(iq.with(), QLatin1String("juliet@capulet.com")); QCOMPARE(iq.start(), QDateTime(QDate(1469, 7, 21), QTime(2, 0, 0), Qt::UTC)); QCOMPARE(iq.end(), QDateTime(QDate(1479, 7, 21), QTime(4, 0, 0), Qt::UTC)); QCOMPARE(iq.resultSetQuery().max(), max); serializePacket(iq, xml); } void tst_QXmppArchiveIq::testArchiveChat_data() { QTest::addColumn("xml"); QTest::addColumn("count"); QTest::newRow("no rsm") << QByteArray( "" "" "Art thou not Romeo, and a Montague?" "Neither, fair saint, if either thee dislike." "How cam'st thou hither, tell me, and wherefore?" "" "") << -1; QTest::newRow("with rsm") << QByteArray( "" "" "Art thou not Romeo, and a Montague?" "Neither, fair saint, if either thee dislike." "How cam'st thou hither, tell me, and wherefore?" "" "3" "" "" "") << 3; } void tst_QXmppArchiveIq::testArchiveChat() { QFETCH(QByteArray, xml); QFETCH(int, count); QXmppArchiveChatIq iq; parsePacket(iq, xml); QCOMPARE(iq.type(), QXmppIq::Result); QCOMPARE(iq.id(), QLatin1String("chat_1")); QCOMPARE(iq.chat().with(), QLatin1String("juliet@capulet.com")); QCOMPARE(iq.chat().messages().size(), 3); QCOMPARE(iq.chat().messages()[0].isReceived(), true); QCOMPARE(iq.chat().messages()[0].body(), QLatin1String("Art thou not Romeo, and a Montague?")); QCOMPARE(iq.chat().messages()[0].date(), QDateTime(QDate(1469, 7, 21), QTime(2, 56, 15), Qt::UTC)); QCOMPARE(iq.chat().messages()[1].isReceived(), false); QCOMPARE(iq.chat().messages()[1].date(), QDateTime(QDate(1469, 7, 21), QTime(2, 56, 26), Qt::UTC)); QCOMPARE(iq.chat().messages()[1].body(), QLatin1String("Neither, fair saint, if either thee dislike.")); QCOMPARE(iq.chat().messages()[2].isReceived(), true); QCOMPARE(iq.chat().messages()[2].date(), QDateTime(QDate(1469, 7, 21), QTime(2, 56, 33), Qt::UTC)); QCOMPARE(iq.chat().messages()[2].body(), QLatin1String("How cam'st thou hither, tell me, and wherefore?")); QCOMPARE(iq.resultSetReply().count(), count); serializePacket(iq, xml); } void tst_QXmppArchiveIq::testArchiveRemove() { const QByteArray xml( "" "" ""); QXmppArchiveRemoveIq iq; parsePacket(iq, xml); QCOMPARE(iq.type(), QXmppIq::Set); QCOMPARE(iq.id(), QLatin1String("remove_1")); QCOMPARE(iq.with(), QLatin1String("juliet@capulet.com")); QCOMPARE(iq.start(), QDateTime(QDate(1469, 7, 21), QTime(2, 0, 0), Qt::UTC)); QCOMPARE(iq.end(), QDateTime(QDate(1479, 7, 21), QTime(4, 0, 0), Qt::UTC)); serializePacket(iq, xml); } void tst_QXmppArchiveIq::testArchiveRetrieve_data() { QTest::addColumn("xml"); QTest::addColumn("max"); QTest::newRow("no rsm") << QByteArray( "" "" "") << -1; QTest::newRow("with rsm") << QByteArray( "" "" "" "30" "" "" "") << 30; } void tst_QXmppArchiveIq::testArchiveRetrieve() { QFETCH(QByteArray, xml); QFETCH(int, max); QXmppArchiveRetrieveIq iq; parsePacket(iq, xml); QCOMPARE(iq.type(), QXmppIq::Get); QCOMPARE(iq.id(), QLatin1String("retrieve_1")); QCOMPARE(iq.with(), QLatin1String("juliet@capulet.com")); QCOMPARE(iq.start(), QDateTime(QDate(1469, 7, 21), QTime(2, 0, 0), Qt::UTC)); QCOMPARE(iq.resultSetQuery().max(), max); serializePacket(iq, xml); } QTEST_MAIN(tst_QXmppArchiveIq) #include "tst_qxmpparchiveiq.moc" qxmpp-0.9.3/tests/qxmppbindiq/000077500000000000000000000000001263006255200163675ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppbindiq/qxmppbindiq.pro000066400000000000000000000001161263006255200214430ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppbindiq SOURCES += tst_qxmppbindiq.cpp qxmpp-0.9.3/tests/qxmppbindiq/tst_qxmppbindiq.cpp000066400000000000000000000047031263006255200223250ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppBindIq.h" #include "util.h" class tst_QXmppBindIq : public QObject { Q_OBJECT private slots: void testNoResource(); void testResource(); void testResult(); }; void tst_QXmppBindIq::testNoResource() { const QByteArray xml( "" "" ""); QXmppBindIq bind; parsePacket(bind, xml); QCOMPARE(bind.type(), QXmppIq::Set); QCOMPARE(bind.id(), QString("bind_1")); QCOMPARE(bind.jid(), QString()); QCOMPARE(bind.resource(), QString()); serializePacket(bind, xml); } void tst_QXmppBindIq::testResource() { const QByteArray xml( "" "" "someresource" "" ""); QXmppBindIq bind; parsePacket(bind, xml); QCOMPARE(bind.type(), QXmppIq::Set); QCOMPARE(bind.id(), QString("bind_2")); QCOMPARE(bind.jid(), QString()); QCOMPARE(bind.resource(), QString("someresource")); serializePacket(bind, xml); } void tst_QXmppBindIq::testResult() { const QByteArray xml( "" "" "somenode@example.com/someresource" "" ""); QXmppBindIq bind; parsePacket(bind, xml); QCOMPARE(bind.type(), QXmppIq::Result); QCOMPARE(bind.id(), QString("bind_2")); QCOMPARE(bind.jid(), QString("somenode@example.com/someresource")); QCOMPARE(bind.resource(), QString()); serializePacket(bind, xml); } QTEST_MAIN(tst_QXmppBindIq) #include "tst_qxmppbindiq.moc" qxmpp-0.9.3/tests/qxmppcallmanager/000077500000000000000000000000001263006255200173675ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppcallmanager/qxmppcallmanager.pro000066400000000000000000000001301263006255200234370ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppcallmanager SOURCES += tst_qxmppcallmanager.cpp qxmpp-0.9.3/tests/qxmppcallmanager/tst_qxmppcallmanager.cpp000066400000000000000000000104271263006255200243250ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppCallManager.h" #include "QXmppClient.h" #include "QXmppServer.h" #include "util.h" //Q_DECLARE_METATYPE(QXmppTransferJob::Method) class tst_QXmppCallManager : public QObject { Q_OBJECT private slots: void init(); void testCall(); void acceptCall(QXmppCall *call); private: QXmppCall *receiverCall; }; void tst_QXmppCallManager::init() { receiverCall = 0; } void tst_QXmppCallManager::acceptCall(QXmppCall *call) { receiverCall = call; call->accept(); } void tst_QXmppCallManager::testCall() { const QString testDomain("localhost"); const QHostAddress testHost(QHostAddress::LocalHost); const quint16 testPort = 12345; QXmppLogger logger; logger.setLoggingType(QXmppLogger::StdoutLogging); // prepare server TestPasswordChecker passwordChecker; passwordChecker.addCredentials("sender", "testpwd"); passwordChecker.addCredentials("receiver", "testpwd"); QXmppServer server; server.setDomain(testDomain); server.setPasswordChecker(&passwordChecker); server.listenForClients(testHost, testPort); // prepare sender QXmppClient sender; QXmppCallManager *senderManager = new QXmppCallManager; sender.addExtension(senderManager); sender.setLogger(&logger); QEventLoop senderLoop; connect(&sender, SIGNAL(connected()), &senderLoop, SLOT(quit())); connect(&sender, SIGNAL(disconnected()), &senderLoop, SLOT(quit())); QXmppConfiguration config; config.setDomain(testDomain); config.setHost(testHost.toString()); config.setPort(testPort); config.setUser("sender"); config.setPassword("testpwd"); sender.connectToServer(config); senderLoop.exec(); QCOMPARE(sender.isConnected(), true); // prepare receiver QXmppClient receiver; QXmppCallManager *receiverManager = new QXmppCallManager; connect(receiverManager, SIGNAL(callReceived(QXmppCall*)), this, SLOT(acceptCall(QXmppCall*))); receiver.addExtension(receiverManager); receiver.setLogger(&logger); QEventLoop receiverLoop; connect(&receiver, SIGNAL(connected()), &receiverLoop, SLOT(quit())); connect(&receiver, SIGNAL(disconnected()), &receiverLoop, SLOT(quit())); config.setUser("receiver"); config.setPassword("testpwd"); receiver.connectToServer(config); receiverLoop.exec(); QCOMPARE(receiver.isConnected(), true); // connect call qDebug() << "======== CONNECT ========"; QEventLoop loop; QXmppCall *senderCall = senderManager->call("receiver@localhost/QXmpp"); QVERIFY(senderCall); connect(senderCall, SIGNAL(connected()), &loop, SLOT(quit())); loop.exec(); QVERIFY(receiverCall); QCOMPARE(senderCall->direction(), QXmppCall::OutgoingDirection); QCOMPARE(senderCall->state(), QXmppCall::ActiveState); QCOMPARE(receiverCall->direction(), QXmppCall::IncomingDirection); QCOMPARE(receiverCall->state(), QXmppCall::ActiveState); // exchange some media qDebug() << "======== TALK ========"; QTimer::singleShot(2000, &loop, SLOT(quit())); loop.exec(); // hangup call qDebug() << "======== HANGUP ========"; connect(senderCall, SIGNAL(finished()), &loop, SLOT(quit())); senderCall->hangup(); loop.exec(); QCOMPARE(senderCall->direction(), QXmppCall::OutgoingDirection); QCOMPARE(senderCall->state(), QXmppCall::FinishedState); QCOMPARE(receiverCall->direction(), QXmppCall::IncomingDirection); QCOMPARE(receiverCall->state(), QXmppCall::FinishedState); } QTEST_MAIN(tst_QXmppCallManager) #include "tst_qxmppcallmanager.moc" qxmpp-0.9.3/tests/qxmppcodec/000077500000000000000000000000001263006255200161765ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppcodec/qxmppcodec.pro000066400000000000000000000001141263006255200210570ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppcodec SOURCES += tst_qxmppcodec.cpp qxmpp-0.9.3/tests/qxmppcodec/tst_qxmppcodec.cpp000066400000000000000000000233331263006255200217430ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppCodec_p.h" class tst_QXmppCodec : public QObject { Q_OBJECT private slots: void testTheoraDecoder(); void testTheoraEncoder(); }; void tst_QXmppCodec::testTheoraDecoder() { #ifdef QXMPP_USE_THEORA QMap params; params.insert("delivery-method", "inline"); params.insert("configuration", "AAAAAcNFrgqZAio6gHRoZW9yYQMCAQAUAA8AAUAAAPAAAAAAAB4AAAABAAAAAAAAAAAAAMDAgXRoZW9yYSsAAABYaXBoLk9yZyBsaWJ0aGVvcmEgMS4xIDIwMDkwODIyIChUaHVzbmVsZGEpAAAAAIJ0aGVvcmG+zSj3uc1rGLWpSUoQc5zmMYxSlKQhCDGMYhCEIQhAAAAAAAAAAAAAEfThZC5VSbR2EvVwtJhrlaKpQJZIodBH05m41mQwF0slUpEslEYiEAeDkcDQZDEWiwVigTCURiEQB4OhwMhgLBUJhIIg8GgwFPuZF9aVVVQUEtLRkZBQTw8NzcyMi0tLSgoKCMjIx4eHh4ZGRkZFBQUFBQPDw8PDw8PCgoKCgoKCgoFBQUFBQUFAIQCwoQGCgzPQwMDhMaOjw3Dg0QGCg5RTgOERYdM1dQPhIWJTpEbWdNGCM3QFFocVwxQE5XZ3l4ZUhcX2JwZGdjERIYL2NjY2MSFRpCY2NjYxgaOGNjY2NjL0JjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjYxAQEBQYHCAoEBAUGBwgKDAQFBgcICgwQBQYHCAoMEBAGBwgKDBAQEAcICgwQEBAYCAoMEBAQGCAKDBAQEBggIA+L8t9ANMxO+Qo3g6om9uWYi3Ucb4D9yiSJe4NjJfWqpGmZXYuxCBORg9o6mS+cw2tWGxlUpXn27h+SdxDTMrsXYghfIo8NVqDYyXj85dzEro9o8k4T7qqQgxXNU+6qkV2NBGcppQe0eddyQ4GVrMbfOH8V4Xgl52/4TjtMPaPOpImMBdWszKag13wyWkKP7QL0KeNjmXZGgdyg9o865Tba72CuClUYEXxJ/xaLWOQfcIh3Nr/cQtI2GYsrQG6clcih7t51JeqpKhHmcJ0rWbBcbxQiuwNJA5PFD3brv/7JjeWwUg9ngWnWdxxYrMYfAZUcjRqJpZNr/6lLc7I4sPg+Tgmlk2jwW8Bn1dAsrAi0x5Mr/6lLchNaPXnYDaiL/gex8voTcwnZ9LbBWuBNLJrpigPMnd6qkQBJr9e5epxNLtQbnWbCJahuFlYaf4o8jvzhVSUoC6M6yYlGvwsrF5OTS7SPO3DmIQ7j3Ng/0tqKUBFc4YvWsosrHki/tu5Cbaj7MRmHQn/0yWw1FKBHCLKzdefak8z9tQiJc2HQtMnunBcx8SOe6iqkWVi+UPvfAbUT/69M8IxFIMuGKbm0XHem8MAX1rNRAdQ8Nvl1QpxWtzzk7RHpKomkj/NMjCfML51dgQ/nTuLbFc+gFNTS0OHKMJpXtEnmuRhvmDVzDe0nK7GNwEe37g7iBM9olk86qU5mT6Baw3AedmwUTeyyRNYb285XiszBy6j0yXH/HxVStYQB9exgJ8m417RdOYRZWuYDwlbFE3skehazf8KqRS+I3nf5O4zQWCu5uwDUmNqPZZImnRaycwmN9QqpGXJ1nCf43BwjCYoba+y6d2K7SDcvnCTyLD4QVKSN3haH7FJ5WscTjl1EhubhmDShtr7NLlf8KXE4xZtESMkJpdtbjm8798H1qysFEOH+4y6gqFVIdtATS7Sa0c3DOG+AfWn56ji6sKzzCduZY8CkRKAbTS6yaQr+jg9y8WmHfI+sVmLOP8gT3N6gsrqU7hPcRgmbay6SZQuC/3wdCjPDtb8cmMX8AqpORJkwx8gN3B7FaOvkLucRlANtZtJc7136ysVUkK17PuQOH0Y8XfrKzovk7cjDEGjbWbOVRlEKqW4DNo21yxlu+hIHDwvYKJvxFYrSdnS17Oj5EFSlwPRiNtWTTOjC/uw3Qq1qe4jRdDyWQTf/cg4ea7p7zE5Im1EMDOsWUqsi5odOwmlk9j/PsLQ+IfOGN5lufnaPXmcWVrjR0iBNLtJ7RgU1GcFotXwHzj9vOBooJCVtNr75hcCOLvnKssqUsWbqEPmWFKo/dQwC5jw3rLLS8CVM21k0jz5PHaJ7ROH11Ko5ZBolTNtZPY394O0SjPw6w4W2FcDcxhnED5/ypqFqGcdntAzGkzbWWTJ1fWWLvDgxwRR7jcn/XcoKikDIbapmmctDHDt1FWWIfjxGeyXuLRuhWi9QMmmZtriwmn7QK7CmoRfHUnI/Jfbo3nAqpHV/Ccwx5H1oQ0d/oBmiDbVIml0jy9LKy7zcU7nnC34CLKG6A5XhIJpW2umceD92xoLKyd71UKXwxJBtqlaTZ5UQt3Dr0PzCNFf4rsE/K1d2gqG9SmAO10XBb0+9EJeSGZtqlaTZMcP/DlOojWVjepSh4CPoSL2DFkNtUzTOX/2Acp11Bb9W8WIux5SqcEhelYDbUymaZ43J7RCi5gHr5R+srI3fW48qUi36Rz6QIVlZGC8mZNM2Btrjd/1EO06WjjcRnIXTF5gyxNM22tFvsiqApHXditKT//ELiJv4KR7CaUdQE7Dg/y+G9xiz5rLAiJCVtNrH35etqFVJcZd+BGCaVtrpJmiov+D9164YYoNy2xWQ8ziqkIyQlNJm2udF7ljgQ+fA7ZRf2j3rjcT3WK4AFGN/6fmBTULV3gJBmaTNtZcsIkfdhWhe9HH243OhiZJjTNtrKowSXo+VNRAefVlhP29uLeD+KEbieT5zEqpIEJ7/aWVjvqNwFAbasmmeLCZfLd4Nx+nXA0zbamFDLG+aSNAcnsv0JVSInltaw764ECRxKQuTr/vcqpLKyITnw21UML1xli0z9meWxg694pVPrQUAbapWk0mcePJDfcgfu2DKIT+WK9xTUgcOoR4n5V2Avju+WqDAkErSY21zyxibvXf4pqHfzq2AekcXKys83IX5ekYMRtrKTNM8riejgLKyLqFTUEb5cXhlM0zlG2uOEjlbRAebvR/P3wEblI+n9VUjfyAhKO4jixWFyVeNM22phMyx/t6DeL0Fr/7vjwsrBKuGWLTM21TML56OUnRAjhVUlKM3d9REBI4sK3JKF0zC/8bamWLTP5Qtn8PYaiqlARiyscb9krkTKJzbV/8MsWmZdawv69InkkIgeWqaghuc/k5gSCZpmbay5Y92Fe4URor/nDr0HX6ckBtqZTNM5WOF91SmAeOfhRFbuWOPVZ3HCKaiH0t58ICNQkJQ0zbamEzLG+7cP++LFZP86iCMAyxaZm2qZhfdL+n+5WVqahD5Abokii164ddj05KFp/MGWLTM21XML5+90FRS8cWEat0l+QopBvGSQxEA4HQY4M8i2dfcmfGuj/blR36WVvJVVI3jJIYiAcDoMcGeRbOvuTPjXR/tyo79LK3kqqkbxkkMRAOB0GODPItnX3Jnxro/25Ud+llbyVVSKqThP1ACJeCZpmbay5SMcIfFlYt5fei7sjo/3BbHDUpeuX9AsrgPNwuSGDEZTNMzbWW+fg7+RdAfz8+UqllYPqIvW8KA4JC9KNM22pMyxwu7RregsrOVr6fwjcJO2/pAhOj9KGEzLFeaZttbqIlNRSeRA+no7cc+hXZHANxafjLFpmTMLzbW6XqSGoQonqyulUgG8jwD5MvunWjXR/sY4M8peXbhR1GQIUZIEoutYXkyic76f/WKwbaueDLFpnv75EqpKqUBGLKxxv2SuRMonNtX/wyxaZl1rC/r0ieSQgA=="); QXmppTheoraDecoder decoder; QCOMPARE(decoder.setParameters(params), true); QXmppVideoFormat format = decoder.format(); QCOMPARE(format.frameSize(), QSize(320, 240)); QCOMPARE(format.pixelFormat(), QXmppVideoFrame::Format_YUV420P); #endif } void tst_QXmppCodec::testTheoraEncoder() { #ifdef QXMPP_USE_THEORA QXmppVideoFormat format; format.setFrameSize(QSize(320, 240)); format.setPixelFormat(QXmppVideoFrame::Format_YUV420P); QXmppTheoraEncoder encoder; encoder.setFormat(format); QMap params = encoder.parameters(); QCOMPARE(params.value("delivery-method"), QLatin1String("inline")); QCOMPARE(params.value("configuration"), QLatin1String("AAAAAcNFrgzoAio6gHRoZW9yYQMCAQAUAA8AAUAAAPAAAAAAAB4AAAABAAAAAAAAAAAAAMDAgXRoZW9yYSsAAABYaXBoLk9yZyBsaWJ0aGVvcmEgMS4xIDIwMDkwODIyIChUaHVzbmVsZGEpAAAAAIJ0aGVvcmG+zSj3uc1rGLWpSUoQc5zmMYxSlKQhCDGMYhCEIQhAAAAAAAAAAAAAEW2uU2eSyPxWEvx4OVts5ir1aKtUKBMpJFoQ/nk5m41mUwl4slUpk4kkghkIfDwdjgajQYC8VioUCQRiIQh8PBwMhgLBQIg4FRba5TZ5LI/FYS/Hg5W2zmKvVoq1QoEykkWhD+eTmbjWZTCXiyVSmTiSSCGQh8PB2OBqNBgLxWKhQJBGIhCHw8HAyGAsFAiDgUCw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDAwPEhQUFQ0NDhESFRUUDg4PEhQVFRUOEBETFBUVFRARFBUVFRUVEhMUFRUVFRUUFRUVFRUVFRUVFRUVFRUVEAwLEBQZGxwNDQ4SFRwcGw4NEBQZHBwcDhATFhsdHRwRExkcHB4eHRQYGxwdHh4dGxwdHR4eHh4dHR0dHh4eHRALChAYKDM9DAwOExo6PDcODRAYKDlFOA4RFh0zV1A+EhYlOkRtZ00YIzdAUWhxXDFATldneXhlSFxfYnBkZ2MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEhIVGRoaGhoSFBYaGhoaGhUWGRoaGhoaGRoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhESFh8kJCQkEhQYIiQkJCQWGCEkJCQkJB8iJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQREhgvY2NjYxIVGkJjY2NjGBo4Y2NjY2MvQmNjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRISEhUXGBkbEhIVFxgZGxwSFRcYGRscHRUXGBkbHB0dFxgZGxwdHR0YGRscHR0dHhkbHB0dHR4eGxwdHR0eHh4REREUFxocIBERFBcaHCAiERQXGhwgIiUUFxocICIlJRcaHCAiJSUlGhwgIiUlJSkcICIlJSUpKiAiJSUlKSoqEBAQFBgcICgQEBQYHCAoMBAUGBwgKDBAFBgcICgwQEAYHCAoMEBAQBwgKDBAQEBgICgwQEBAYIAoMEBAQGCAgAfF5cdH1e3Ow/L66wGmYnfIUbwdUTe3LMRbqON8B+5RJEvcGxkvrVUjTMrsXYhAnIwe0dTJfOYbWrDYyqUrz7dw/JO4hpmV2LsQQvkUeGq1BsZLx+cu5iV0e0eScJ91VIQYrmqfdVSK7GgjOU0oPaPOu5IcDK1mNvnD+K8LwS87f8Jx2mHtHnUkTGAurWZlNQa74ZLSFH9oF6FPGxzLsjQO5Qe0edcpttd7BXBSqMCL4k/4tFrHIPuEQ7m1/uIWkbDMWVoDdOSuRQ9286kvVUlQjzOE6VrNguN4oRXYGkgcnih7t13/9kxvLYKQezwLTrO44sVmMPgMqORo1E0sm1/9SludkcWHwfJwTSybR4LeAz6ugWVgRaY8mV/9SluQmtHrzsBtRF/wPY+X0JuYTs+ltgrXAmlk10xQHmTu9VSIAk1+vcvU4ml2oNzrNhEtQ3CysNP8UeR35wqpKUBdGdZMSjX4WVi8nJpdpHnbhzEIdx7mwf6W1FKAiucMXrWUWVjyRf23chNtR9mIzDoT/6ZLYailAjhFlZuvPtSeZ+2oREubDoWmT3TguY+JHPdRVSLKxfKH3vgNqJ/9emeEYikGXDFNzaLjvTeGAL61mogOoeG3y6oU4rW55ydoj0lUTSR/mmRhPmF86uwIfzp3FtiufQCmppaHDlGE0r2iTzXIw3zBq5hvaTldjG4CPb9wdxAme0SyedVKczJ9AtYbgPOzYKJvZZImsN7ecrxWZg5dR6ZLj/j4qpWsIA+vYwE+Tca9ounMIsrXMB4Stiib2SPQtZv+FVIpfEbzv8ncZoLBXc3YBqTG1HsskTTotZOYTG+oVUjLk6zhP8bg4RhMUNtfZdO7FdpBuXzhJ5Fh8IKlJG7wtD9ik8rWOJxy6iQ3NwzBpQ219mlyv+FLicYs2iJGSE0u2txzed++D61ZWCiHD/cZdQVCqkO2gJpdpNaObhnDfAPrT89RxdWFZ5hO3MseBSIlANppdZNIV/Rwe5eLTDvkfWKzFnH+QJ7m9QWV1KdwnuIwTNtZdJMoXBf74OhRnh2t+OTGL+AVUnIkyYY+QG7g9itHXyF3OIygG2s2kud679ZWKqSFa9n3IHD6MeLv1lZ0XyduRhiDRtrNnKoyiFVLcBm0ba5Yy3fQkDh4XsFE34isVpOzpa9nR8iCpS4HoxG2rJpnRhf3YboVa1PcRouh5LIJv/uQcPNd095ickTaiGBnWLKVWRc0OnYTSyex/n2FofEPnDG8y3PztHrzOLK1xo6RAml2k9owKajOC0Wr4D5x+3nA0UEhK2m198wuBHF3zlWWVKWLN1CHzLClUfuoYBcx4b1llpeBKmbayaR58njtE9onD66lUcsg0Spm2snsb+8HaJRn4dYcLbCuBuYwziB8/5U1C1DOOz2gZjSZtrLJk6vrLF3hwY4Io9xuT/ruUFRSBkNtUzTOWhjh26irLEPx4jPZL3Fo3QrReoGTTM21xYTT9oFdhTUIvjqTkfkvt0bzgVUjq/hOYY8j60IaO/0AzRBtqkTS6R5ellZd5uKdzzhb8BFlDdAcrwkE0rbXTOPB+7Y0FlZO96qFL4Ykg21StJs8qIW7h16H5hGiv8V2Cflau7QVDepTAHa6Lgt6feiEvJDM21StJsmOH/hynURrKxvUpQ8BH0JF7BiyG2qZpnL/7AOU66gt+reLEXY8pVOCQvSsBtqZTNM8bk9ohRcwD18o/WVkbvrceVKRb9I59IEKysjBeTMmmbA21xu/6iHadLRxuIzkLpi8wZYmmbbWi32RVAUjruxWlJ//iFxE38FI9hNKOoCdhwf5fDe4xZ81lgREhK2m1j78vW1CqkuMu/AjBNK210kzRUX/B+69cMMUG5bYrIeZxVSEZISmkzbXOi9yxwIfPgdsov7R71xuJ7rFcACjG/9PzApqFq7wEgzNJm2suWESPuwrQvejj7cbnQxMkxpm21lUYJL0fKmogPPqywn7e3FvB/FCNxPJ85iVUkCE9/tLKx31G4CgNtWTTPFhMvlu8G4/TrgaZttTChljfNJGgOT2X6EqpETy2tYd9cCBI4lIXJ1/3uVUllZEJz4baqGF64yxaZ+zPLYwde8Uqn1oKANtUrSaTOPHkhvuQP3bBlEJ/LFe4pqQOHUI8T8q7AXx3fLVBgSCVpMba55YxN3rv8U1Dv51bAPSOLlZWebkL8vSMGI21lJmmeVxPRwFlZF1CpqCN8uLwymaZyjbXHCRytogPN3o/n74CNykfT+qqRv5AQlHcRxYrC5KvGmbbUwmZY/29BvF6C1/93x4WVglXDLFpmbapmF89HKTogRwqqSlGbu+oiAkcWFbklC6Zhf+NtTLFpn8oWz+HsNRVSgIxZWON+yVyJlE5tq/+GWLTMutYX9ekTySEQPLVNQQ3OfycwJBM0zNtZcse7CvcKI0V/zh16Dr9OSA21MpmmcrHC+6pTAPHPwoit3LHHqs7jhFNRD6W8+EBGoSEoaZttTCZljfduH/fFisn+dRBGAZYtMzbVMwvul/T/crK1NQh8gN0SRRa9cOux6clC0/mDLFpmbarmF8/e6CopeOLCNW6S/IUUg3jJIYiAcDoMcGeRbOvuTPjXR/tyo79LK3kqqkbxkkMRAOB0GODPItnX3Jnxro/25Ud+llbyVVSN4ySGIgHA6DHBnkWzr7kz410f7cqO/Syt5KqpFVJwn6gBEvBM0zNtZcpGOEPiysW8vvRd2R0f7gtjhqUvXL+gWVwHm4XJDBiMpmmZtrLfPwd/IugP5+fKVSysH1EXreFAcEhelGmbbUmZY4Xdo1vQWVnK19P4RuEnbf0gQnR+lDCZlivNM22t1ESmopPIgfT0duOfQrsjgG4tPxli0zJmF5trdL1JDUIUT1ZXSqQDeR4B8mX3TrRro/2McGeUvLtwo6jIEKMkCUXWsLyZROd9P/rFYNtXPBli0z398iVUlVKAjFlY437JXImUTm2r/4ZYtMy61hf16RPJIQ==")); #endif } QTEST_MAIN(tst_QXmppCodec) #include "tst_qxmppcodec.moc" qxmpp-0.9.3/tests/qxmppdataform/000077500000000000000000000000001263006255200167165ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppdataform/qxmppdataform.pro000066400000000000000000000001221263006255200223160ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppdataform SOURCES += tst_qxmppdataform.cpp qxmpp-0.9.3/tests/qxmppdataform/tst_qxmppdataform.cpp000066400000000000000000000073561263006255200232120ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Andrey Batyiev * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppDataForm.h" #include "util.h" class tst_QXmppDataForm : public QObject { Q_OBJECT private slots: void testSimple(); void testSubmit(); void testMedia(); }; void tst_QXmppDataForm::testSimple() { const QByteArray xml( "" "Joggle Search" "Fill out this form to search for information!" "" "" "" ""); QXmppDataForm form; parsePacket(form, xml); QCOMPARE(form.isNull(), false); QCOMPARE(form.title(), QLatin1String("Joggle Search")); QCOMPARE(form.instructions(), QLatin1String("Fill out this form to search for information!")); QCOMPARE(form.fields().size(), 1); QCOMPARE(form.fields().at(0).type(), QXmppDataForm::Field::TextSingleField); QCOMPARE(form.fields().at(0).isRequired(), true); QCOMPARE(form.fields().at(0).key(), QString("search_request")); serializePacket(form, xml); } void tst_QXmppDataForm::testSubmit() { const QByteArray xml( "" "" "verona" "" ""); QXmppDataForm form; parsePacket(form, xml); QCOMPARE(form.isNull(), false); serializePacket(form, xml); } void tst_QXmppDataForm::testMedia() { const QByteArray xml( "" "" "" "" "" "http://www.victim.com/challenges/ocr.jpeg?F3A6292C" "" "" "cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org" "" "" "" ""); QXmppDataForm form; parsePacket(form, xml); QCOMPARE(form.isNull(), false); QCOMPARE(form.fields().size(), 1); QCOMPARE(form.fields().at(0).type(), QXmppDataForm::Field::TextSingleField); QCOMPARE(form.fields().at(0).isRequired(), false); QCOMPARE(form.fields().at(0).media().uris().size(), 2); QCOMPARE(form.fields().at(0).media().isNull(), false); QCOMPARE(form.fields().at(0).media().height(), 80); QCOMPARE(form.fields().at(0).media().width(), 290); QCOMPARE(form.fields().at(0).media().uris().at(0).first, QString("image/jpeg")); QCOMPARE(form.fields().at(0).media().uris().at(0).second, QString("http://www.victim.com/challenges/ocr.jpeg?F3A6292C")); QCOMPARE(form.fields().at(0).media().uris().at(1).first, QString("image/png")); QCOMPARE(form.fields().at(0).media().uris().at(1).second, QString("cid:sha1+f24030b8d91d233bac14777be5ab531ca3b9f102@bob.xmpp.org")); serializePacket(form, xml); } QTEST_MAIN(tst_QXmppDataForm) #include "tst_qxmppdataform.moc" qxmpp-0.9.3/tests/qxmppdiscoveryiq/000077500000000000000000000000001263006255200174625ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppdiscoveryiq/qxmppdiscoveryiq.pro000066400000000000000000000001301263006255200236250ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppdiscoveryiq SOURCES += tst_qxmppdiscoveryiq.cpp qxmpp-0.9.3/tests/qxmppdiscoveryiq/tst_qxmppdiscoveryiq.cpp000066400000000000000000000067021263006255200245140ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppDiscoveryIq.h" #include "util.h" class tst_QXmppDiscoveryIq : public QObject { Q_OBJECT private slots: void testDiscovery(); void testDiscoveryWithForm(); }; void tst_QXmppDiscoveryIq::testDiscovery() { const QByteArray xml( "" "" "" "" "" "" "" "" ""); QXmppDiscoveryIq disco; parsePacket(disco, xml); QCOMPARE(disco.verificationString(), QByteArray::fromBase64("QgayPKawpkPSDYmwT/WM94uAlu0=")); serializePacket(disco, xml); } void tst_QXmppDiscoveryIq::testDiscoveryWithForm() { const QByteArray xml( "" "" "" "" "" "" "" "" "" "" "urn:xmpp:dataforms:softwareinfo" "" "" "ipv4" "ipv6" "" "" "Mac" "" "" "10.5.1" "" "" "Psi" "" "" "0.11" "" "" "" ""); QXmppDiscoveryIq disco; parsePacket(disco, xml); QCOMPARE(disco.verificationString(), QByteArray::fromBase64("q07IKJEyjvHSyhy//CH0CxmKi8w=")); serializePacket(disco, xml); } QTEST_MAIN(tst_QXmppDiscoveryIq) #include "tst_qxmppdiscoveryiq.moc" qxmpp-0.9.3/tests/qxmppentitytimeiq/000077500000000000000000000000001263006255200176465ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppentitytimeiq/qxmppentitytimeiq.pro000066400000000000000000000001321263006255200241770ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppentitytimeiq SOURCES += tst_qxmppentitytimeiq.cpp qxmpp-0.9.3/tests/qxmppentitytimeiq/tst_qxmppentitytimeiq.cpp000066400000000000000000000046441263006255200250670ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppEntityTimeIq.h" #include "util.h" class tst_QXmppEntityTimeIq : public QObject { Q_OBJECT private slots: void testEntityTimeGet(); void testEntityTimeResult(); }; void tst_QXmppEntityTimeIq::testEntityTimeGet() { const QByteArray xml("" ""); QXmppEntityTimeIq entityTime; parsePacket(entityTime, xml); QCOMPARE(entityTime.id(), QLatin1String("time_1")); QCOMPARE(entityTime.to(), QLatin1String("juliet@capulet.com/balcony")); QCOMPARE(entityTime.from(), QLatin1String("romeo@montague.net/orchard")); QCOMPARE(entityTime.type(), QXmppIq::Get); serializePacket(entityTime, xml); } void tst_QXmppEntityTimeIq::testEntityTimeResult() { const QByteArray xml( "" "" ""); QXmppEntityTimeIq entityTime; parsePacket(entityTime, xml); QCOMPARE(entityTime.id(), QLatin1String("time_1")); QCOMPARE(entityTime.from(), QLatin1String("juliet@capulet.com/balcony")); QCOMPARE(entityTime.to(), QLatin1String("romeo@montague.net/orchard")); QCOMPARE(entityTime.type(), QXmppIq::Result); QCOMPARE(entityTime.tzo(), -21600); QCOMPARE(entityTime.utc(), QDateTime(QDate(2006, 12, 19), QTime(17, 58, 35), Qt::UTC)); serializePacket(entityTime, xml); } QTEST_MAIN(tst_QXmppEntityTimeIq) #include "tst_qxmppentitytimeiq.moc" qxmpp-0.9.3/tests/qxmppiceconnection/000077500000000000000000000000001263006255200177415ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppiceconnection/qxmppiceconnection.pro000066400000000000000000000001341263006255200243670ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppiceconnection SOURCES += tst_qxmppiceconnection.cpp qxmpp-0.9.3/tests/qxmppiceconnection/tst_qxmppiceconnection.cpp000066400000000000000000000123011263006255200252420ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppStun.h" #include "util.h" class tst_QXmppIceConnection : public QObject { Q_OBJECT private slots: void testBind(); void testBindStun(); void testConnect(); }; void tst_QXmppIceConnection::testBind() { const int componentId = 1024; QXmppLogger logger; logger.setLoggingType(QXmppLogger::StdoutLogging); QXmppIceConnection client; connect(&client, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), &logger, SLOT(log(QXmppLogger::MessageType,QString))); client.setIceControlling(true); client.addComponent(componentId); QXmppIceComponent *component = client.component(componentId); QVERIFY(component); QCOMPARE(client.gatheringState(), QXmppIceConnection::NewGatheringState); client.bind(QXmppIceComponent::discoverAddresses()); QCOMPARE(client.gatheringState(), QXmppIceConnection::CompleteGatheringState); QCOMPARE(client.localCandidates().size(), component->localCandidates().size()); QVERIFY(!client.localCandidates().isEmpty()); foreach (const QXmppJingleCandidate &c, client.localCandidates()) { QCOMPARE(c.component(), componentId); QCOMPARE(c.type(), QXmppJingleCandidate::HostType); } } void tst_QXmppIceConnection::testBindStun() { const int componentId = 1024; QXmppLogger logger; logger.setLoggingType(QXmppLogger::StdoutLogging); QHostInfo stunInfo = QHostInfo::fromName("stun.l.google.com"); QVERIFY(!stunInfo.addresses().isEmpty()); QXmppIceConnection client; connect(&client, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), &logger, SLOT(log(QXmppLogger::MessageType,QString))); client.setIceControlling(true); client.setStunServer(stunInfo.addresses().first(), 19302); client.addComponent(componentId); QXmppIceComponent *component = client.component(componentId); QVERIFY(component); QCOMPARE(client.gatheringState(), QXmppIceConnection::NewGatheringState); client.bind(QXmppIceComponent::discoverAddresses()); QCOMPARE(client.gatheringState(), QXmppIceConnection::BusyGatheringState); QEventLoop loop; connect(&client, SIGNAL(gatheringStateChanged()), &loop, SLOT(quit())); loop.exec(); bool foundReflexive = false; QCOMPARE(client.gatheringState(), QXmppIceConnection::CompleteGatheringState); QCOMPARE(client.localCandidates().size(), component->localCandidates().size()); QVERIFY(!client.localCandidates().isEmpty()); foreach (const QXmppJingleCandidate &c, client.localCandidates()) { QCOMPARE(c.component(), componentId); if (c.type() == QXmppJingleCandidate::ServerReflexiveType) foundReflexive = true; else QCOMPARE(c.type(), QXmppJingleCandidate::HostType); } QVERIFY(foundReflexive); } void tst_QXmppIceConnection::testConnect() { const int componentId = 1024; QXmppLogger logger; logger.setLoggingType(QXmppLogger::StdoutLogging); QXmppIceConnection clientL; connect(&clientL, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), &logger, SLOT(log(QXmppLogger::MessageType,QString))); clientL.setIceControlling(true); clientL.addComponent(componentId); clientL.bind(QXmppIceComponent::discoverAddresses()); QXmppIceConnection clientR; connect(&clientR, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), &logger, SLOT(log(QXmppLogger::MessageType,QString))); clientR.setIceControlling(false); clientR.addComponent(componentId); clientR.bind(QXmppIceComponent::discoverAddresses()); // exchange credentials clientL.setRemoteUser(clientR.localUser()); clientL.setRemotePassword(clientR.localPassword()); clientR.setRemoteUser(clientL.localUser()); clientR.setRemotePassword(clientL.localPassword()); // exchange candidates foreach (const QXmppJingleCandidate &candidate, clientR.localCandidates()) clientL.addRemoteCandidate(candidate); foreach (const QXmppJingleCandidate &candidate, clientL.localCandidates()) clientR.addRemoteCandidate(candidate); // start ICE QEventLoop loop; connect(&clientL, SIGNAL(connected()), &loop, SLOT(quit())); connect(&clientR, SIGNAL(connected()), &loop, SLOT(quit())); clientL.connectToHost(); clientR.connectToHost(); // check both clients are connected loop.exec(); loop.exec(); QVERIFY(clientL.isConnected()); QVERIFY(clientR.isConnected()); } QTEST_MAIN(tst_QXmppIceConnection) #include "tst_qxmppiceconnection.moc" qxmpp-0.9.3/tests/qxmppiq/000077500000000000000000000000001263006255200155325ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppiq/qxmppiq.pro000066400000000000000000000001061263006255200177500ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppiq SOURCES += tst_qxmppiq.cpp qxmpp-0.9.3/tests/qxmppiq/tst_qxmppiq.cpp000066400000000000000000000037511263006255200206350ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppIq.h" #include "util.h" class tst_QXmppIq : public QObject { Q_OBJECT private slots: void testBasic_data(); void testBasic(); }; void tst_QXmppIq::testBasic_data() { QTest::addColumn("xml"); QTest::addColumn("type"); QTest::newRow("get") << QByteArray("") << int(QXmppIq::Get); QTest::newRow("set") << QByteArray("") << int(QXmppIq::Set); QTest::newRow("result") << QByteArray("") << int(QXmppIq::Result); QTest::newRow("error") << QByteArray("") << int(QXmppIq::Error); } void tst_QXmppIq::testBasic() { QFETCH(QByteArray, xml); QFETCH(int, type); QXmppIq iq; parsePacket(iq, xml); QCOMPARE(iq.to(), QString("foo@example.com/QXmpp")); QCOMPARE(iq.from(), QString("bar@example.com/QXmpp")); QCOMPARE(int(iq.type()), type); serializePacket(iq, xml); } QTEST_MAIN(tst_QXmppIq) #include "tst_qxmppiq.moc" qxmpp-0.9.3/tests/qxmppjingleiq/000077500000000000000000000000001263006255200167235ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppjingleiq/qxmppjingleiq.pro000066400000000000000000000001221263006255200223300ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppjingleiq SOURCES += tst_qxmppjingleiq.cpp qxmpp-0.9.3/tests/qxmppjingleiq/tst_qxmppjingleiq.cpp000066400000000000000000000512301263006255200232120ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppJingleIq.h" #include "util.h" class tst_QXmppJingleIq : public QObject { Q_OBJECT private slots: void testCandidate(); void testContent(); void testContentFingerprint(); void testContentSdp(); void testContentSdpReflexive(); void testContentSdpFingerprint(); void testContentSdpParameters(); void testSession(); void testTerminate(); void testAudioPayloadType(); void testVideoPayloadType(); void testRinging(); }; void tst_QXmppJingleIq::testCandidate() { const QByteArray xml( ""); QXmppJingleCandidate candidate; parsePacket(candidate, xml); QCOMPARE(candidate.foundation(), QLatin1String("1")); QCOMPARE(candidate.generation(), 0); QCOMPARE(candidate.id(), QLatin1String("el0747fg11")); QCOMPARE(candidate.host(), QHostAddress("10.0.1.1")); QCOMPARE(candidate.network(), 1); QCOMPARE(candidate.port(), quint16(8998)); QCOMPARE(candidate.priority(), 2130706431); QCOMPARE(candidate.protocol(), QLatin1String("udp")); QCOMPARE(candidate.type(), QXmppJingleCandidate::HostType); serializePacket(candidate, xml); }; void tst_QXmppJingleIq::testContent() { const QByteArray xml( "" "" "" "" "" "" "" "" "" "" "" "" "" ""); QXmppJingleIq::Content content; parsePacket(content, xml); QCOMPARE(content.creator(), QLatin1String("initiator")); QCOMPARE(content.name(), QLatin1String("voice")); QCOMPARE(content.descriptionMedia(), QLatin1String("audio")); QCOMPARE(content.descriptionSsrc(), quint32(0)); QCOMPARE(content.payloadTypes().size(), 6); QCOMPARE(content.payloadTypes()[0].id(), quint8(96)); QCOMPARE(content.payloadTypes()[1].id(), quint8(97)); QCOMPARE(content.payloadTypes()[2].id(), quint8(18)); QCOMPARE(content.payloadTypes()[3].id(), quint8(0)); QCOMPARE(content.payloadTypes()[4].id(), quint8(103)); QCOMPARE(content.payloadTypes()[5].id(), quint8(98)); QCOMPARE(content.transportCandidates().size(), 2); QCOMPARE(content.transportCandidates()[0].component(), 1); QCOMPARE(content.transportCandidates()[0].foundation(), QLatin1String("1")); QCOMPARE(content.transportCandidates()[0].host(), QHostAddress("10.0.1.1")); QCOMPARE(content.transportCandidates()[0].port(), quint16(8998)); QCOMPARE(content.transportCandidates()[0].priority(), 2130706431); QCOMPARE(content.transportCandidates()[0].protocol(), QLatin1String("udp")); QCOMPARE(content.transportCandidates()[0].type(), QXmppJingleCandidate::HostType); QCOMPARE(content.transportCandidates()[1].component(), 1); QCOMPARE(content.transportCandidates()[1].foundation(), QLatin1String("2")); QCOMPARE(content.transportCandidates()[1].host(), QHostAddress("192.0.2.3")); QCOMPARE(content.transportCandidates()[1].port(), quint16(45664)); QCOMPARE(content.transportCandidates()[1].priority(), 1694498815); QCOMPARE(content.transportCandidates()[1].protocol(), QLatin1String("udp")); QCOMPARE(content.transportCandidates()[1].type(), QXmppJingleCandidate::ServerReflexiveType); QCOMPARE(content.transportUser(), QLatin1String("8hhy")); QCOMPARE(content.transportPassword(), QLatin1String("asd88fgpdd777uzjYhagZg")); serializePacket(content, xml); } void tst_QXmppJingleIq::testContentFingerprint() { const QByteArray xml( "" "" "" "" "" "" "" "02:1A:CC:54:27:AB:EB:9C:53:3F:3E:4B:65:2E:7D:46:3F:54:42:CD:54:F1:7A:03:A2:7D:F9:B0:7F:46:19:B2" "" "" ""); QXmppJingleIq::Content content; parsePacket(content, xml); QCOMPARE(content.creator(), QLatin1String("initiator")); QCOMPARE(content.name(), QLatin1String("voice")); QCOMPARE(content.descriptionMedia(), QLatin1String("audio")); QCOMPARE(content.descriptionSsrc(), quint32(0)); QCOMPARE(content.payloadTypes().size(), 1); QCOMPARE(content.payloadTypes()[0].id(), quint8(0)); QCOMPARE(content.transportCandidates().size(), 1); QCOMPARE(content.transportCandidates()[0].component(), 1); QCOMPARE(content.transportCandidates()[0].foundation(), QLatin1String("1")); QCOMPARE(content.transportCandidates()[0].host(), QHostAddress("10.0.1.1")); QCOMPARE(content.transportCandidates()[0].port(), quint16(8998)); QCOMPARE(content.transportCandidates()[0].priority(), 2130706431); QCOMPARE(content.transportCandidates()[0].protocol(), QLatin1String("udp")); QCOMPARE(content.transportCandidates()[0].type(), QXmppJingleCandidate::HostType); QCOMPARE(content.transportUser(), QLatin1String("8hhy")); QCOMPARE(content.transportPassword(), QLatin1String("asd88fgpdd777uzjYhagZg")); QCOMPARE(content.transportFingerprint(), QByteArray::fromHex("021acc5427abeb9c533f3e4b652e7d463f5442cd54f17a03a27df9b07f4619b2")); QCOMPARE(content.transportFingerprintHash(), QLatin1String("sha-256")); QCOMPARE(content.transportFingerprintSetup(), QLatin1String("actpass")); serializePacket(content, xml); } void tst_QXmppJingleIq::testContentSdp() { const QString sdp( "m=audio 8998 RTP/AVP 96 97 18 0 103 98\r\n" "c=IN IP4 10.0.1.1\r\n" "a=rtpmap:96 speex/16000\r\n" "a=rtpmap:97 speex/8000\r\n" "a=rtpmap:18 G729/0\r\n" "a=rtpmap:0 PCMU/0\r\n" "a=rtpmap:103 L16/16000/2\r\n" "a=rtpmap:98 x-ISAC/8000\r\n" "a=candidate:1 1 udp 2130706431 10.0.1.1 8998 typ host generation 0\r\n" "a=candidate:2 1 udp 1694498815 192.0.2.3 45664 typ host generation 0\r\n" "a=ice-ufrag:8hhy\r\n" "a=ice-pwd:asd88fgpdd777uzjYhagZg\r\n"); QXmppJingleIq::Content content; QVERIFY(content.parseSdp(sdp)); QCOMPARE(content.descriptionMedia(), QLatin1String("audio")); QCOMPARE(content.descriptionSsrc(), quint32(0)); QCOMPARE(content.payloadTypes().size(), 6); QCOMPARE(content.payloadTypes()[0].id(), quint8(96)); QCOMPARE(content.payloadTypes()[1].id(), quint8(97)); QCOMPARE(content.payloadTypes()[2].id(), quint8(18)); QCOMPARE(content.payloadTypes()[3].id(), quint8(0)); QCOMPARE(content.payloadTypes()[4].id(), quint8(103)); QCOMPARE(content.payloadTypes()[5].id(), quint8(98)); QCOMPARE(content.transportCandidates().size(), 2); QCOMPARE(content.transportCandidates()[0].component(), 1); QCOMPARE(content.transportCandidates()[0].foundation(), QLatin1String("1")); QCOMPARE(content.transportCandidates()[0].host(), QHostAddress("10.0.1.1")); QCOMPARE(content.transportCandidates()[0].port(), quint16(8998)); QCOMPARE(content.transportCandidates()[0].priority(), 2130706431); QCOMPARE(content.transportCandidates()[0].protocol(), QLatin1String("udp")); QCOMPARE(content.transportCandidates()[0].type(), QXmppJingleCandidate::HostType); QCOMPARE(content.transportCandidates()[1].component(), 1); QCOMPARE(content.transportCandidates()[1].foundation(), QLatin1String("2")); QCOMPARE(content.transportCandidates()[1].host(), QHostAddress("192.0.2.3")); QCOMPARE(content.transportCandidates()[1].port(), quint16(45664)); QCOMPARE(content.transportCandidates()[1].priority(), 1694498815); QCOMPARE(content.transportCandidates()[1].protocol(), QLatin1String("udp")); QCOMPARE(content.transportCandidates()[1].type(), QXmppJingleCandidate::HostType); QCOMPARE(content.transportUser(), QLatin1String("8hhy")); QCOMPARE(content.transportPassword(), QLatin1String("asd88fgpdd777uzjYhagZg")); QCOMPARE(content.toSdp(), sdp); } void tst_QXmppJingleIq::testContentSdpReflexive() { const QString sdp( "m=audio 45664 RTP/AVP 96 97 18 0 103 98\r\n" "c=IN IP4 192.0.2.3\r\n" "a=rtpmap:96 speex/16000\r\n" "a=rtpmap:97 speex/8000\r\n" "a=rtpmap:18 G729/0\r\n" "a=rtpmap:0 PCMU/0\r\n" "a=rtpmap:103 L16/16000/2\r\n" "a=rtpmap:98 x-ISAC/8000\r\n" "a=candidate:1 1 udp 2130706431 10.0.1.1 8998 typ host generation 0\r\n" "a=candidate:2 1 udp 1694498815 192.0.2.3 45664 typ srflx generation 0\r\n" "a=ice-ufrag:8hhy\r\n" "a=ice-pwd:asd88fgpdd777uzjYhagZg\r\n"); QXmppJingleIq::Content content; QVERIFY(content.parseSdp(sdp)); QCOMPARE(content.descriptionMedia(), QLatin1String("audio")); QCOMPARE(content.descriptionSsrc(), quint32(0)); QCOMPARE(content.payloadTypes().size(), 6); QCOMPARE(content.payloadTypes()[0].id(), quint8(96)); QCOMPARE(content.payloadTypes()[1].id(), quint8(97)); QCOMPARE(content.payloadTypes()[2].id(), quint8(18)); QCOMPARE(content.payloadTypes()[3].id(), quint8(0)); QCOMPARE(content.payloadTypes()[4].id(), quint8(103)); QCOMPARE(content.payloadTypes()[5].id(), quint8(98)); QCOMPARE(content.transportCandidates().size(), 2); QCOMPARE(content.transportCandidates()[0].component(), 1); QCOMPARE(content.transportCandidates()[0].foundation(), QLatin1String("1")); QCOMPARE(content.transportCandidates()[0].host(), QHostAddress("10.0.1.1")); QCOMPARE(content.transportCandidates()[0].port(), quint16(8998)); QCOMPARE(content.transportCandidates()[0].priority(), 2130706431); QCOMPARE(content.transportCandidates()[0].protocol(), QLatin1String("udp")); QCOMPARE(content.transportCandidates()[0].type(), QXmppJingleCandidate::HostType); QCOMPARE(content.transportCandidates()[1].component(), 1); QCOMPARE(content.transportCandidates()[1].foundation(), QLatin1String("2")); QCOMPARE(content.transportCandidates()[1].host(), QHostAddress("192.0.2.3")); QCOMPARE(content.transportCandidates()[1].port(), quint16(45664)); QCOMPARE(content.transportCandidates()[1].priority(), 1694498815); QCOMPARE(content.transportCandidates()[1].protocol(), QLatin1String("udp")); QCOMPARE(content.transportCandidates()[1].type(), QXmppJingleCandidate::ServerReflexiveType); QCOMPARE(content.transportUser(), QLatin1String("8hhy")); QCOMPARE(content.transportPassword(), QLatin1String("asd88fgpdd777uzjYhagZg")); QCOMPARE(content.toSdp(), sdp); } void tst_QXmppJingleIq::testContentSdpFingerprint() { const QString sdp( "m=audio 8998 RTP/AVP 96 100\r\n" "c=IN IP4 10.0.1.1\r\n" "a=rtpmap:96 speex/16000\r\n" "a=fmtp:96 cng=on; vbr=on\r\n" "a=rtpmap:100 telephone-event/8000\r\n" "a=fmtp:100 0-15,66,70\r\n" "a=candidate:1 1 udp 2130706431 10.0.1.1 8998 typ host generation 0\r\n" "a=fingerprint:sha-256 02:1A:CC:54:27:AB:EB:9C:53:3F:3E:4B:65:2E:7D:46:3F:54:42:CD:54:F1:7A:03:A2:7D:F9:B0:7F:46:19:B2\r\n" "a=setup:actpass\r\n"); QXmppJingleIq::Content content; QVERIFY(content.parseSdp(sdp)); QCOMPARE(content.descriptionMedia(), QLatin1String("audio")); QCOMPARE(content.descriptionSsrc(), quint32(0)); QCOMPARE(content.payloadTypes().size(), 2); QCOMPARE(content.payloadTypes()[0].id(), quint8(96)); QCOMPARE(content.payloadTypes()[0].parameters().value("vbr"), QLatin1String("on")); QCOMPARE(content.payloadTypes()[0].parameters().value("cng"), QLatin1String("on")); QCOMPARE(content.payloadTypes()[1].id(), quint8(100)); QCOMPARE(content.payloadTypes()[1].parameters().value("events"), QLatin1String("0-15,66,70")); QCOMPARE(content.transportCandidates().size(), 1); QCOMPARE(content.transportCandidates()[0].component(), 1); QCOMPARE(content.transportCandidates()[0].foundation(), QLatin1String("1")); QCOMPARE(content.transportCandidates()[0].host(), QHostAddress("10.0.1.1")); QCOMPARE(content.transportCandidates()[0].port(), quint16(8998)); QCOMPARE(content.transportCandidates()[0].priority(), 2130706431); QCOMPARE(content.transportCandidates()[0].protocol(), QLatin1String("udp")); QCOMPARE(content.transportCandidates()[0].type(), QXmppJingleCandidate::HostType); QCOMPARE(content.transportFingerprint(), QByteArray::fromHex("021acc5427abeb9c533f3e4b652e7d463f5442cd54f17a03a27df9b07f4619b2")); QCOMPARE(content.transportFingerprintHash(), QLatin1String("sha-256")); QCOMPARE(content.transportFingerprintSetup(), QLatin1String("actpass")); QCOMPARE(content.toSdp(), sdp); } void tst_QXmppJingleIq::testContentSdpParameters() { const QString sdp( "m=audio 8998 RTP/AVP 96 100\r\n" "c=IN IP4 10.0.1.1\r\n" "a=rtpmap:96 speex/16000\r\n" "a=fmtp:96 cng=on; vbr=on\r\n" "a=rtpmap:100 telephone-event/8000\r\n" "a=fmtp:100 0-15,66,70\r\n" "a=candidate:1 1 udp 2130706431 10.0.1.1 8998 typ host generation 0\r\n"); QXmppJingleIq::Content content; QVERIFY(content.parseSdp(sdp)); QCOMPARE(content.descriptionMedia(), QLatin1String("audio")); QCOMPARE(content.descriptionSsrc(), quint32(0)); QCOMPARE(content.payloadTypes().size(), 2); QCOMPARE(content.payloadTypes()[0].id(), quint8(96)); QCOMPARE(content.payloadTypes()[0].parameters().value("vbr"), QLatin1String("on")); QCOMPARE(content.payloadTypes()[0].parameters().value("cng"), QLatin1String("on")); QCOMPARE(content.payloadTypes()[1].id(), quint8(100)); QCOMPARE(content.payloadTypes()[1].parameters().value("events"), QLatin1String("0-15,66,70")); QCOMPARE(content.transportCandidates().size(), 1); QCOMPARE(content.transportCandidates()[0].component(), 1); QCOMPARE(content.transportCandidates()[0].foundation(), QLatin1String("1")); QCOMPARE(content.transportCandidates()[0].host(), QHostAddress("10.0.1.1")); QCOMPARE(content.transportCandidates()[0].port(), quint16(8998)); QCOMPARE(content.transportCandidates()[0].priority(), 2130706431); QCOMPARE(content.transportCandidates()[0].protocol(), QLatin1String("udp")); QCOMPARE(content.transportCandidates()[0].type(), QXmppJingleCandidate::HostType); QCOMPARE(content.toSdp(), sdp); } void tst_QXmppJingleIq::testSession() { const QByteArray xml( "" "" "" "" "" "" "" ""); QXmppJingleIq session; parsePacket(session, xml); QCOMPARE(session.action(), QXmppJingleIq::SessionInitiate); QCOMPARE(session.initiator(), QLatin1String("romeo@montague.lit/orchard")); QCOMPARE(session.sid(), QLatin1String("a73sjjvkla37jfea")); QCOMPARE(session.contents().size(), 1); QCOMPARE(session.contents()[0].creator(), QLatin1String("initiator")); QCOMPARE(session.contents()[0].name(), QLatin1String("this-is-a-stub")); QCOMPARE(session.reason().text(), QString()); QCOMPARE(session.reason().type(), QXmppJingleIq::Reason::None); serializePacket(session, xml); } void tst_QXmppJingleIq::testTerminate() { const QByteArray xml( "" "" "" "" "" "" ""); QXmppJingleIq session; parsePacket(session, xml); QCOMPARE(session.action(), QXmppJingleIq::SessionTerminate); QCOMPARE(session.initiator(), QString()); QCOMPARE(session.sid(), QLatin1String("a73sjjvkla37jfea")); QCOMPARE(session.reason().text(), QString()); QCOMPARE(session.reason().type(), QXmppJingleIq::Reason::Success); serializePacket(session, xml); } void tst_QXmppJingleIq::testAudioPayloadType() { const QByteArray xml(""); QXmppJinglePayloadType payload; parsePacket(payload, xml); QCOMPARE(payload.id(), static_cast(103)); QCOMPARE(payload.name(), QLatin1String("L16")); QCOMPARE(payload.channels(), static_cast(2)); QCOMPARE(payload.clockrate(), 16000u); serializePacket(payload, xml); } void tst_QXmppJingleIq::testVideoPayloadType() { const QByteArray xml( "" "" "" ""); QXmppJinglePayloadType payload; parsePacket(payload, xml); QCOMPARE(payload.id(), static_cast(98)); QCOMPARE(payload.name(), QLatin1String("theora")); QCOMPARE(payload.clockrate(), 90000u); QCOMPARE(payload.parameters().size(), 2); QCOMPARE(payload.parameters().value("height"), QLatin1String("768")); QCOMPARE(payload.parameters().value("width"), QLatin1String("1024")); serializePacket(payload, xml); } void tst_QXmppJingleIq::testRinging() { const QByteArray xml( "" "" "" "" ""); QXmppJingleIq iq; parsePacket(iq, xml); QCOMPARE(iq.ringing(), true); serializePacket(iq, xml); } QTEST_MAIN(tst_QXmppJingleIq) #include "tst_qxmppjingleiq.moc" qxmpp-0.9.3/tests/qxmppmessage/000077500000000000000000000000001263006255200165455ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppmessage/qxmppmessage.pro000066400000000000000000000001201263006255200217720ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppmessage SOURCES += tst_qxmppmessage.cpp qxmpp-0.9.3/tests/qxmppmessage/tst_qxmppmessage.cpp000066400000000000000000000534221263006255200226630ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppMessage.h" #include "util.h" class tst_QXmppMessage : public QObject { Q_OBJECT private slots: void testBasic_data(); void testBasic(); void testMessageAttention(); void testMessageReceipt(); void testDelay_data(); void testDelay(); void testDelayWithMultipleStamp(); void testExtendedAddresses(); void testMucInvitation(); void testState_data(); void testState(); void testXhtml(); void testSubextensions(); void testChatMarkers(); }; void tst_QXmppMessage::testBasic_data() { QTest::addColumn("xml"); QTest::addColumn("type"); QTest::addColumn("body"); QTest::addColumn("subject"); QTest::addColumn("thread"); QTest::newRow("error") << QByteArray("") << int(QXmppMessage::Error) << QString() << QString() << QString(); QTest::newRow("normal") << QByteArray("") << int(QXmppMessage::Normal) << QString() << QString() << QString(); QTest::newRow("chat") << QByteArray("") << int(QXmppMessage::Chat) << QString() << QString() << QString(); QTest::newRow("groupchat") << QByteArray("") << int(QXmppMessage::GroupChat) << QString() << QString() << QString(); QTest::newRow("headline") << QByteArray("") << int(QXmppMessage::Headline) << QString() << QString() << QString(); QTest::newRow("full") << QByteArray("" "test subject" "test body & stuff" "test thread" "") << int(QXmppMessage::Normal) << "test body & stuff" << "test subject" << "test thread"; } void tst_QXmppMessage::testBasic() { QFETCH(QByteArray, xml); QFETCH(int, type); QFETCH(QString, body); QFETCH(QString, subject); QFETCH(QString, thread); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.to(), QString("foo@example.com/QXmpp")); QCOMPARE(message.from(), QString("bar@example.com/QXmpp")); QVERIFY(message.extendedAddresses().isEmpty()); QCOMPARE(int(message.type()), type); QCOMPARE(message.body(), body); QCOMPARE(message.subject(), subject); QCOMPARE(message.thread(), thread); QCOMPARE(message.state(), QXmppMessage::None); QCOMPARE(message.isAttentionRequested(), false); QCOMPARE(message.isReceiptRequested(), false); QCOMPARE(message.receiptId(), QString()); QCOMPARE(message.xhtml(), QString()); serializePacket(message, xml); } void tst_QXmppMessage::testMessageAttention() { const QByteArray xml( "" "" ""); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.to(), QString("foo@example.com/QXmpp")); QCOMPARE(message.from(), QString("bar@example.com/QXmpp")); QVERIFY(message.extendedAddresses().isEmpty()); QCOMPARE(message.type(), QXmppMessage::Normal); QCOMPARE(message.body(), QString()); QCOMPARE(message.isAttentionRequested(), true); QCOMPARE(message.isReceiptRequested(), false); QCOMPARE(message.receiptId(), QString()); serializePacket(message, xml); } void tst_QXmppMessage::testMessageReceipt() { const QByteArray xml( "" "My lord, dispatch; read o'er these articles." "" ""); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.id(), QString("richard2-4.1.247")); QCOMPARE(message.to(), QString("kingrichard@royalty.england.lit/throne")); QCOMPARE(message.from(), QString("northumberland@shakespeare.lit/westminster")); QVERIFY(message.extendedAddresses().isEmpty()); QCOMPARE(message.type(), QXmppMessage::Normal); QCOMPARE(message.body(), QString("My lord, dispatch; read o'er these articles.")); QCOMPARE(message.isAttentionRequested(), false); QCOMPARE(message.isReceiptRequested(), true); QCOMPARE(message.receiptId(), QString()); serializePacket(message, xml); const QByteArray receiptXml( "" "" ""); QXmppMessage receipt; parsePacket(receipt, receiptXml); QCOMPARE(receipt.id(), QString("bi29sg183b4v")); QCOMPARE(receipt.to(), QString("northumberland@shakespeare.lit/westminster")); QCOMPARE(receipt.from(), QString("kingrichard@royalty.england.lit/throne")); QVERIFY(receipt.extendedAddresses().isEmpty()); QCOMPARE(receipt.type(), QXmppMessage::Normal); QCOMPARE(receipt.body(), QString()); QCOMPARE(receipt.isAttentionRequested(), false); QCOMPARE(receipt.isReceiptRequested(), false); QCOMPARE(receipt.receiptId(), QString("richard2-4.1.247")); serializePacket(receipt, receiptXml); const QByteArray oldXml( "" "" ""); QXmppMessage old; parsePacket(old, oldXml); QCOMPARE(old.id(), QString("richard2-4.1.247")); QCOMPARE(old.to(), QString("northumberland@shakespeare.lit/westminster")); QCOMPARE(old.from(), QString("kingrichard@royalty.england.lit/throne")); QVERIFY(old.extendedAddresses().isEmpty()); QCOMPARE(old.type(), QXmppMessage::Normal); QCOMPARE(old.body(), QString()); QCOMPARE(old.isAttentionRequested(), false); QCOMPARE(old.isReceiptRequested(), false); QCOMPARE(old.receiptId(), QString("richard2-4.1.247")); } void tst_QXmppMessage::testDelay_data() { QTest::addColumn("xml"); QTest::addColumn("stamp"); QTest::newRow("delay") << QByteArray("" "" "") << QDateTime(QDate(2010, 06, 29), QTime(8, 23, 6), Qt::UTC); QTest::newRow("legacy") << QByteArray("" "" "") << QDateTime(QDate(2010, 06, 29), QTime(8, 23, 6), Qt::UTC); } void tst_QXmppMessage::testDelay() { QFETCH(QByteArray, xml); QFETCH(QDateTime, stamp); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.stamp(), stamp); serializePacket(message, xml); } void tst_QXmppMessage::testDelayWithMultipleStamp() { // the XEP-0203 should override XEP-0091's value since XEP-0091 was no more standard protocol QByteArray xml( "" "" "" ""); QByteArray resultXml( "" "" ""); QXmppMessage message; parsePacket(message, xml); qDebug() << message.stamp(); QCOMPARE(message.stamp(), QDateTime(QDate(2010, 06, 29), QTime(8, 23, 6, 123), Qt::UTC)); serializePacket(message, resultXml); } void tst_QXmppMessage::testExtendedAddresses() { QByteArray xml( "" "" "
" "
" "" ""); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.extendedAddresses().size(), 2); QCOMPARE(message.extendedAddresses()[0].description(), QLatin1String("Joe Hildebrand")); QCOMPARE(message.extendedAddresses()[0].jid(), QLatin1String("hildjj@jabber.org/Work")); QCOMPARE(message.extendedAddresses()[0].type(), QLatin1String("to")); QCOMPARE(message.extendedAddresses()[1].description(), QLatin1String("Jeremie Miller")); QCOMPARE(message.extendedAddresses()[1].jid(), QLatin1String("jer@jabber.org/Home")); QCOMPARE(message.extendedAddresses()[1].type(), QLatin1String("cc")); serializePacket(message, xml); } void tst_QXmppMessage::testMucInvitation() { QByteArray xml( "" "" ""); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.mucInvitationJid(), QLatin1String("darkcave@macbeth.shakespeare.lit")); QCOMPARE(message.mucInvitationPassword(), QLatin1String("cauldronburn")); QCOMPARE(message.mucInvitationReason(), QLatin1String("Hey Hecate, this is the place for all good witches!")); serializePacket(message, xml); } void tst_QXmppMessage::testState_data() { QTest::addColumn("xml"); QTest::addColumn("state"); QTest::newRow("none") << QByteArray("") << int(QXmppMessage::None); QTest::newRow("active") << QByteArray("") << int(QXmppMessage::Active); QTest::newRow("inactive") << QByteArray("") << int(QXmppMessage::Inactive); QTest::newRow("gone") << QByteArray("") << int(QXmppMessage::Gone); QTest::newRow("composing") << QByteArray("") << int(QXmppMessage::Composing); QTest::newRow("paused") << QByteArray("") << int(QXmppMessage::Paused); } void tst_QXmppMessage::testState() { QFETCH(QByteArray, xml); QFETCH(int, state); QXmppMessage message; parsePacket(message, xml); QCOMPARE(int(message.state()), state); serializePacket(message, xml); } void tst_QXmppMessage::testXhtml() { const QByteArray xml("" "hi!" "" "" "

hi!

" "" "" "
"); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.xhtml(), QLatin1String("

hi!

")); serializePacket(message, xml); } void tst_QXmppMessage::testSubextensions() { const QByteArray xml("" "" "" "" "" "What man art thou that thus bescreen'd in night so stumblest on my counsel?" "" "" "" ""); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.extensions().size(), 1); QCOMPARE(message.extensions().first().tagName(), QLatin1String("result")); serializePacket(message, xml); } void tst_QXmppMessage::testChatMarkers() { const QByteArray markableXml( "" "sleeping" "My lord, dispatch; read o'er these articles." "" ""); QXmppMessage markableMessage; parsePacket(markableMessage, markableXml); QCOMPARE(markableMessage.isMarkable(), true); QCOMPARE(markableMessage.marker(), QXmppMessage::NoMarker); QCOMPARE(markableMessage.id(), QString("message-1")); QCOMPARE(markableMessage.markedId(), QString()); QCOMPARE(markableMessage.thread(), QString("sleeping")); QCOMPARE(markableMessage.markedThread(), QString()); const QByteArray receivedXml( "" "" ""); QXmppMessage receivedMessage; parsePacket(receivedMessage, receivedXml); QCOMPARE(receivedMessage.isMarkable(), false); QCOMPARE(receivedMessage.marker(), QXmppMessage::Received); QCOMPARE(receivedMessage.id(), QString("message-2")); QCOMPARE(receivedMessage.markedId(), QString("message-1")); QCOMPARE(receivedMessage.thread(), QString()); QCOMPARE(receivedMessage.markedThread(), QString("sleeping")); const QByteArray displayedXml( "" "" ""); QXmppMessage displayedMessage; parsePacket(displayedMessage, displayedXml); QCOMPARE(displayedMessage.isMarkable(), false); QCOMPARE(displayedMessage.marker(), QXmppMessage::Displayed); QCOMPARE(displayedMessage.id(), QString("message-2")); QCOMPARE(displayedMessage.markedId(), QString("message-1")); QCOMPARE(displayedMessage.thread(), QString()); QCOMPARE(displayedMessage.markedThread(), QString("sleeping")); const QByteArray acknowledgedXml( "" "" ""); QXmppMessage acknowledgedMessage; parsePacket(acknowledgedMessage, acknowledgedXml); QCOMPARE(acknowledgedMessage.isMarkable(), false); QCOMPARE(acknowledgedMessage.marker(), QXmppMessage::Acknowledged); QCOMPARE(acknowledgedMessage.id(), QString("message-2")); QCOMPARE(acknowledgedMessage.markedId(), QString("message-1")); QCOMPARE(acknowledgedMessage.thread(), QString()); QCOMPARE(acknowledgedMessage.markedThread(), QString("sleeping")); const QByteArray emptyThreadXml( "" "" ""); QXmppMessage emptyThreadMessage; parsePacket(emptyThreadMessage, emptyThreadXml); QCOMPARE(emptyThreadMessage.isMarkable(), false); QCOMPARE(emptyThreadMessage.marker(), QXmppMessage::Received); QCOMPARE(emptyThreadMessage.id(), QString("message-2")); QCOMPARE(emptyThreadMessage.markedId(), QString("message-1")); QCOMPARE(emptyThreadMessage.thread(), QString()); QCOMPARE(emptyThreadMessage.markedThread(), QString()); const QByteArray notMarkableSerialisation( ""); QXmppMessage serialisationMessage; serialisationMessage.setFrom("kingrichard@royalty.england.lit/throne"); serialisationMessage.setTo("northumberland@shakespeare.lit/westminster"); serialisationMessage.setId("message-3"); serialisationMessage.setMarkable(false); serializePacket(serialisationMessage, notMarkableSerialisation); const QByteArray markableSerialisation( "" "" ""); serialisationMessage.setMarkable(true); serializePacket(serialisationMessage, markableSerialisation); const QByteArray receivedSerialisation( "" "" ""); serialisationMessage.setMarkable(false); serialisationMessage.setMarker(QXmppMessage::Received); serialisationMessage.setMarkerId("message-2"); serializePacket(serialisationMessage, receivedSerialisation); const QByteArray receivedThreadSerialisation( "" "" ""); serialisationMessage.setMarker(QXmppMessage::Received); serialisationMessage.setMarkerId("message-2"); serialisationMessage.setMarkedThread("sleeping"); serializePacket(serialisationMessage, receivedThreadSerialisation); const QByteArray displayedThreadSerialisation( "" "" ""); serialisationMessage.setMarker(QXmppMessage::Displayed); serialisationMessage.setMarkerId("message-2"); serialisationMessage.setMarkedThread("sleeping"); serializePacket(serialisationMessage, displayedThreadSerialisation); const QByteArray acknowledgedThreadSerialisation( "" "" ""); serialisationMessage.setMarker(QXmppMessage::Acknowledged); serialisationMessage.setMarkerId("message-2"); serialisationMessage.setMarkedThread("sleeping"); serializePacket(serialisationMessage, acknowledgedThreadSerialisation); } QTEST_MAIN(tst_QXmppMessage) #include "tst_qxmppmessage.moc" qxmpp-0.9.3/tests/qxmppnonsaslauthiq/000077500000000000000000000000001263006255200200125ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppnonsaslauthiq/qxmppnonsaslauthiq.pro000066400000000000000000000001341263006255200245110ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppnonsaslauthiq SOURCES += tst_qxmppnonsaslauthiq.cpp qxmpp-0.9.3/tests/qxmppnonsaslauthiq/tst_qxmppnonsaslauthiq.cpp000066400000000000000000000052531263006255200253740ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppNonSASLAuth.h" #include "util.h" class tst_QXmppNonSASLAuthIq : public QObject { Q_OBJECT private slots: void testGet(); void testSetPlain(); void testSetDigest(); }; void tst_QXmppNonSASLAuthIq::testGet() { // Client requests authentication fields from server const QByteArray xml( "" "" ""); QXmppNonSASLAuthIq iq; parsePacket(iq, xml); serializePacket(iq, xml); } void tst_QXmppNonSASLAuthIq::testSetPlain() { // Client provides required information (plain) const QByteArray xml( "" "" "bill" "Calli0pe" "globe" "" ""); QXmppNonSASLAuthIq iq; parsePacket(iq, xml); QCOMPARE(iq.username(), QLatin1String("bill")); QCOMPARE(iq.digest(), QByteArray()); QCOMPARE(iq.password(), QLatin1String("Calli0pe")); QCOMPARE(iq.resource(), QLatin1String("globe")); serializePacket(iq, xml); } void tst_QXmppNonSASLAuthIq::testSetDigest() { // Client provides required information (digest) const QByteArray xml( "" "" "bill" "48fc78be9ec8f86d8ce1c39c320c97c21d62334d" "globe" "" ""); QXmppNonSASLAuthIq iq; parsePacket(iq, xml); QCOMPARE(iq.username(), QLatin1String("bill")); QCOMPARE(iq.digest(), QByteArray("\x48\xfc\x78\xbe\x9e\xc8\xf8\x6d\x8c\xe1\xc3\x9c\x32\x0c\x97\xc2\x1d\x62\x33\x4d")); QCOMPARE(iq.password(), QString()); QCOMPARE(iq.resource(), QLatin1String("globe")); serializePacket(iq, xml); } QTEST_MAIN(tst_QXmppNonSASLAuthIq) #include "tst_qxmppnonsaslauthiq.moc" qxmpp-0.9.3/tests/qxmpppresence/000077500000000000000000000000001263006255200167255ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmpppresence/qxmpppresence.pro000066400000000000000000000001221263006255200223340ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmpppresence SOURCES += tst_qxmpppresence.cpp qxmpp-0.9.3/tests/qxmpppresence/tst_qxmpppresence.cpp000066400000000000000000000255321263006255200232240ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Olivier Goffart * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppPresence.h" #include "util.h" class tst_QXmppPresence : public QObject { Q_OBJECT private slots: void testPresence(); void testPresence_data(); void testPresenceWithCapability(); void testPresenceWithExtendedAddresses(); void testPresenceWithMucItem(); void testPresenceWithMucPassword(); void testPresenceWithMucSupport(); }; void tst_QXmppPresence::testPresence_data() { QXmppPresence foo; QTest::addColumn("xml"); QTest::addColumn("type"); QTest::addColumn("priority"); QTest::addColumn("statusType"); QTest::addColumn("statusText"); QTest::addColumn("vcardUpdate"); QTest::addColumn("photoHash"); // presence type QTest::newRow("available") << QByteArray("") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); QTest::newRow("unavailable") << QByteArray("") << int(QXmppPresence::Unavailable) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); QTest::newRow("error") << QByteArray("") << int(QXmppPresence::Error) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); QTest::newRow("subscribe") << QByteArray("") << int(QXmppPresence::Subscribe) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); QTest::newRow("unsubscribe") << QByteArray("") << int(QXmppPresence::Unsubscribe) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); QTest::newRow("subscribed") << QByteArray("") << int(QXmppPresence::Subscribed) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); QTest::newRow("unsubscribed") << QByteArray("") << int(QXmppPresence::Unsubscribed) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); QTest::newRow("probe") << QByteArray("") << int(QXmppPresence::Probe) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); // status text + priority QTest::newRow("full") << QByteArray("awayIn a meeting5") << int(QXmppPresence::Available) << 5 << int(QXmppPresence::Away) << "In a meeting" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); // status type QTest::newRow("away") << QByteArray("away") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Away) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); QTest::newRow("dnd") << QByteArray("dnd") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::DND) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); QTest::newRow("chat") << QByteArray("chat") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Chat) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); QTest::newRow("xa") << QByteArray("xa") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::XA) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); QTest::newRow("invisible") << QByteArray("invisible") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Invisible) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray(); // photo QTest::newRow("vcard-photo") << QByteArray( "" "" "73b908bc" "" "") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateValidPhoto) << QByteArray::fromHex("73b908bc"); QTest::newRow("vard-not-ready") << QByteArray( "" "" "") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNotReady) << QByteArray(); } void tst_QXmppPresence::testPresence() { QFETCH(QByteArray, xml); QFETCH(int, type); QFETCH(int, priority); QFETCH(int, statusType); QFETCH(QString, statusText); QFETCH(int, vcardUpdate); QFETCH(QByteArray, photoHash); QXmppPresence presence; parsePacket(presence, xml); QCOMPARE(int(presence.type()), type); QCOMPARE(presence.priority(), priority); QCOMPARE(int(presence.availableStatusType()), statusType); QCOMPARE(presence.statusText(), statusText); QCOMPARE(int(presence.vCardUpdateType()), vcardUpdate); QCOMPARE(presence.photoHash(), photoHash); serializePacket(presence, xml); } void tst_QXmppPresence::testPresenceWithCapability() { const QByteArray xml( "" "away" "In a meeting" "5" "" "73b908bc" "" "" ""); QXmppPresence presence; parsePacket(presence, xml); QCOMPARE(presence.to(), QString("foo@example.com/QXmpp")); QCOMPARE(presence.from(), QString("bar@example.com/QXmpp")); QCOMPARE(presence.availableStatusType(), QXmppPresence::Away); QCOMPARE(presence.statusText(), QString("In a meeting")); QCOMPARE(presence.priority(), 5); QCOMPARE(presence.photoHash(), QByteArray::fromHex("73b908bc")); QCOMPARE(presence.vCardUpdateType(), QXmppPresence::VCardUpdateValidPhoto); QCOMPARE(presence.capabilityHash(), QString("sha-1")); QCOMPARE(presence.capabilityNode(), QString("https://github.com/qxmpp-project/qxmpp")); QCOMPARE(presence.capabilityVer(), QByteArray::fromBase64("QgayPKawpkPSDYmwT/WM94uAlu0=")); serializePacket(presence, xml); } void tst_QXmppPresence::testPresenceWithExtendedAddresses() { const QByteArray xml( "" "" "
" "
" "" ""); QXmppPresence presence; parsePacket(presence, xml); QCOMPARE(presence.extendedAddresses().size(), 2); QCOMPARE(presence.extendedAddresses()[0].description(), QString()); QCOMPARE(presence.extendedAddresses()[0].jid(), QLatin1String("temas@jabber.org")); QCOMPARE(presence.extendedAddresses()[0].type(), QLatin1String("bcc")); QCOMPARE(presence.extendedAddresses()[1].description(), QString()); QCOMPARE(presence.extendedAddresses()[1].jid(), QLatin1String("jer@jabber.org")); QCOMPARE(presence.extendedAddresses()[1].type(), QLatin1String("bcc")); serializePacket(presence, xml); } void tst_QXmppPresence::testPresenceWithMucItem() { const QByteArray xml( "" "" "" "" "Avaunt, you cullion!" "" "" "" ""); QXmppPresence presence; parsePacket(presence, xml); QCOMPARE(presence.to(), QLatin1String("pistol@shakespeare.lit/harfleur")); QCOMPARE(presence.from(), QLatin1String("harfleur@henryv.shakespeare.lit/pistol")); QCOMPARE(presence.type(), QXmppPresence::Unavailable); QCOMPARE(presence.mucItem().actor(), QLatin1String("fluellen@shakespeare.lit")); QCOMPARE(presence.mucItem().affiliation(), QXmppMucItem::NoAffiliation); QCOMPARE(presence.mucItem().jid(), QString()); QCOMPARE(presence.mucItem().reason(), QLatin1String("Avaunt, you cullion!")); QCOMPARE(presence.mucItem().role(), QXmppMucItem::NoRole); QCOMPARE(presence.mucStatusCodes(), QList() << 307); serializePacket(presence, xml); } void tst_QXmppPresence::testPresenceWithMucPassword() { const QByteArray xml( "" "" "pass" "" ""); QXmppPresence presence; parsePacket(presence, xml); QCOMPARE(presence.to(), QLatin1String("coven@chat.shakespeare.lit/thirdwitch")); QCOMPARE(presence.from(), QLatin1String("hag66@shakespeare.lit/pda")); QCOMPARE(presence.type(), QXmppPresence::Available); QCOMPARE(presence.isMucSupported(), true); QCOMPARE(presence.mucPassword(), QLatin1String("pass")); serializePacket(presence, xml); } void tst_QXmppPresence::testPresenceWithMucSupport() { const QByteArray xml( "" "" ""); QXmppPresence presence; parsePacket(presence, xml); QCOMPARE(presence.to(), QLatin1String("coven@chat.shakespeare.lit/thirdwitch")); QCOMPARE(presence.from(), QLatin1String("hag66@shakespeare.lit/pda")); QCOMPARE(presence.type(), QXmppPresence::Available); QCOMPARE(presence.isMucSupported(), true); QVERIFY(presence.mucPassword().isEmpty()); serializePacket(presence, xml); } QTEST_MAIN(tst_QXmppPresence) #include "tst_qxmpppresence.moc" qxmpp-0.9.3/tests/qxmpppubsubiq/000077500000000000000000000000001263006255200167535ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmpppubsubiq/qxmpppubsubiq.pro000066400000000000000000000001221263006255200224100ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmpppubsubiq SOURCES += tst_qxmpppubsubiq.cpp qxmpp-0.9.3/tests/qxmpppubsubiq/tst_qxmpppubsubiq.cpp000066400000000000000000000203641263006255200232760ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppPubSubIq.h" #include "util.h" class tst_QXmppPubSubIq : public QObject { Q_OBJECT private slots: void testItems(); void testItemsResponse(); void testPublish(); void testRetractItem(); void testSubscribe(); void testSubscription(); void testSubscriptions(); }; void tst_QXmppPubSubIq::testItems() { const QByteArray xml( "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("items1")); QCOMPARE(iq.to(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.from(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.type(), QXmppIq::Get); QCOMPARE(iq.queryType(), QXmppPubSubIq::ItemsQuery); QCOMPARE(iq.queryJid(), QString()); QCOMPARE(iq.queryNode(), QLatin1String("storage:bookmarks")); serializePacket(iq, xml); } void tst_QXmppPubSubIq::testItemsResponse() { const QByteArray xml( "" "" "" "" "" "" "JC" "" "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("items1")); QCOMPARE(iq.to(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.from(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.type(), QXmppIq::Result); QCOMPARE(iq.queryType(), QXmppPubSubIq::ItemsQuery); QCOMPARE(iq.queryJid(), QString()); QCOMPARE(iq.queryNode(), QLatin1String("storage:bookmarks")); serializePacket(iq, xml); } void tst_QXmppPubSubIq::testPublish() { const QByteArray xml( "" "" "" "" "" "" "JC" "" "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("items1")); QCOMPARE(iq.to(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.from(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.type(), QXmppIq::Result); QCOMPARE(iq.queryType(), QXmppPubSubIq::PublishQuery); QCOMPARE(iq.queryJid(), QString()); QCOMPARE(iq.queryNode(), QLatin1String("storage:bookmarks")); serializePacket(iq, xml); } void tst_QXmppPubSubIq::testRetractItem() { const QByteArray xml( "" "" "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QString("retract1")); QCOMPARE(iq.to(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.from(), QLatin1String("hamlet@denmark.lit/elsinore")); QCOMPARE(iq.type(), QXmppIq::Set); QCOMPARE(iq.queryType(), QXmppPubSubIq::RetractQuery); QCOMPARE(iq.queryJid(), QString()); QCOMPARE(iq.queryNode(), QLatin1String("princely_musings")); QCOMPARE(iq.items().size(), 1); QCOMPARE(iq.items().at(0).id(), QString("ae890ac52d0df67ed7cfdf51b644e901")); serializePacket(iq, xml); } void tst_QXmppPubSubIq::testSubscribe() { const QByteArray xml( "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("sub1")); QCOMPARE(iq.to(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.from(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.type(), QXmppIq::Set); QCOMPARE(iq.queryType(), QXmppPubSubIq::SubscribeQuery); QCOMPARE(iq.queryJid(), QLatin1String("francisco@denmark.lit")); QCOMPARE(iq.queryNode(), QLatin1String("princely_musings")); serializePacket(iq, xml); } void tst_QXmppPubSubIq::testSubscription() { const QByteArray xml( "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("sub1")); QCOMPARE(iq.to(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.from(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.type(), QXmppIq::Result); QCOMPARE(iq.queryType(), QXmppPubSubIq::SubscriptionQuery); QCOMPARE(iq.queryJid(), QLatin1String("francisco@denmark.lit")); QCOMPARE(iq.queryNode(), QLatin1String("princely_musings")); QCOMPARE(iq.subscriptionId(), QLatin1String("ba49252aaa4f5d320c24d3766f0bdcade78c78d3")); serializePacket(iq, xml); } void tst_QXmppPubSubIq::testSubscriptions() { const QByteArray xml( "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("subscriptions1")); QCOMPARE(iq.to(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.from(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.type(), QXmppIq::Get); QCOMPARE(iq.queryType(), QXmppPubSubIq::SubscriptionsQuery); QCOMPARE(iq.queryJid(), QString()); QCOMPARE(iq.queryNode(), QString()); serializePacket(iq, xml); } QTEST_MAIN(tst_QXmppPubSubIq) #include "tst_qxmpppubsubiq.moc" qxmpp-0.9.3/tests/qxmppregisteriq/000077500000000000000000000000001263006255200172775ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppregisteriq/qxmppregisteriq.pro000066400000000000000000000001261263006255200232640ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppregisteriq SOURCES += tst_qxmppregisteriq.cpp qxmpp-0.9.3/tests/qxmppregisteriq/tst_qxmppregisteriq.cpp000066400000000000000000000154711263006255200241510ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppRegisterIq.h" #include "util.h" class tst_QXmppRegisterIq : public QObject { Q_OBJECT private slots: void testGet(); void testResult(); void testResultWithForm(); void testSet(); void testSetWithForm(); }; void tst_QXmppRegisterIq::testGet() { const QByteArray xml( "" "" ""); QXmppRegisterIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("reg1")); QCOMPARE(iq.to(), QLatin1String("shakespeare.lit")); QCOMPARE(iq.from(), QString()); QCOMPARE(iq.type(), QXmppIq::Get); QCOMPARE(iq.instructions(), QString()); QVERIFY(iq.username().isNull()); QVERIFY(iq.password().isNull()); QVERIFY(iq.email().isNull()); QVERIFY(iq.form().isNull()); serializePacket(iq, xml); } void tst_QXmppRegisterIq::testResult() { const QByteArray xml( "" "" "Choose a username and password for use with this service. Please also provide your email address." "" "" "" "" ""); QXmppRegisterIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("reg1")); QCOMPARE(iq.to(), QString()); QCOMPARE(iq.from(), QString()); QCOMPARE(iq.type(), QXmppIq::Result); QCOMPARE(iq.instructions(), QLatin1String("Choose a username and password for use with this service. Please also provide your email address.")); QVERIFY(!iq.username().isNull()); QVERIFY(iq.username().isEmpty()); QVERIFY(!iq.password().isNull()); QVERIFY(iq.password().isEmpty()); QVERIFY(!iq.email().isNull()); QVERIFY(iq.email().isEmpty()); QVERIFY(iq.form().isNull()); serializePacket(iq, xml); } void tst_QXmppRegisterIq::testResultWithForm() { const QByteArray xml( "" "" "Use the enclosed form to register. If your Jabber client does not support Data Forms, visit http://www.shakespeare.lit/contests.php" "" "Contest Registration" "" "Please provide the following information" "to sign up for our special contests!" "" "" "jabber:iq:register" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""); QXmppRegisterIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("reg3")); QCOMPARE(iq.to(), QLatin1String("juliet@capulet.com/balcony")); QCOMPARE(iq.from(), QLatin1String("contests.shakespeare.lit")); QCOMPARE(iq.type(), QXmppIq::Result); QCOMPARE(iq.instructions(), QLatin1String("Use the enclosed form to register. If your Jabber client does not support Data Forms, visit http://www.shakespeare.lit/contests.php")); QVERIFY(iq.username().isNull()); QVERIFY(iq.password().isNull()); QVERIFY(iq.email().isNull()); QVERIFY(!iq.form().isNull()); QCOMPARE(iq.form().title(), QLatin1String("Contest Registration")); serializePacket(iq, xml); } void tst_QXmppRegisterIq::testSet() { const QByteArray xml( "" "" "bill" "Calliope" "bard@shakespeare.lit" "" ""); QXmppRegisterIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("reg2")); QCOMPARE(iq.to(), QString()); QCOMPARE(iq.from(), QString()); QCOMPARE(iq.type(), QXmppIq::Set); QCOMPARE(iq.username(), QLatin1String("bill")); QCOMPARE(iq.password(), QLatin1String("Calliope")); QCOMPARE(iq.email(), QLatin1String("bard@shakespeare.lit")); QVERIFY(iq.form().isNull()); serializePacket(iq, xml); } void tst_QXmppRegisterIq::testSetWithForm() { const QByteArray xml( "" "" "" "" "jabber:iq:register" "" "" "Juliet" "" "" "Capulet" "" "" "juliet@capulet.com" "" "" "F" "" "" "" ""); QXmppRegisterIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("reg4")); QCOMPARE(iq.to(), QLatin1String("contests.shakespeare.lit")); QCOMPARE(iq.from(), QLatin1String("juliet@capulet.com/balcony")); QCOMPARE(iq.type(), QXmppIq::Set); QVERIFY(iq.username().isNull()); QVERIFY(iq.password().isNull()); QVERIFY(iq.email().isNull()); QVERIFY(!iq.form().isNull()); serializePacket(iq, xml); } QTEST_MAIN(tst_QXmppRegisterIq) #include "tst_qxmppregisteriq.moc" qxmpp-0.9.3/tests/qxmppresultset/000077500000000000000000000000001263006255200171535ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppresultset/qxmppresultset.pro000066400000000000000000000001241263006255200230120ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppresultset SOURCES += tst_qxmppresultset.cpp qxmpp-0.9.3/tests/qxmppresultset/tst_qxmppresultset.cpp000066400000000000000000000125711263006255200236770ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Olivier Goffart * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppResultSet.h" #include "util.h" class tst_QXmppResultSet : public QObject { Q_OBJECT private slots: void testQuery_data(); void testQuery(); void testReply_data(); void testReply(); }; void tst_QXmppResultSet::testQuery_data() { QTest::addColumn("xml"); QTest::addColumn("max"); QTest::addColumn("index"); QTest::addColumn("before"); QTest::addColumn("after"); QTest::newRow("Example 3") << QByteArray("" "10" "") << 10 << -1 << QString() << QString(); QTest::newRow("Example 5") << QByteArray("" "10" "peterpan@neverland.lit" "") << 10 << -1 << QString() << QString("peterpan@neverland.lit"); QTest::newRow("Example 5") << QByteArray("" "10" "peter@pixyland.org" "") << 10 << -1 << QString("peter@pixyland.org") << QString(); QTest::newRow("Example 11") << QByteArray("" "10" "" "") << 10 << -1 << QString("") << QString(); QTest::newRow("Example 12") << QByteArray("" "10" "371" "") << 10 << 371 << QString() << QString(); QTest::newRow("Example 15") << QByteArray("" "0" "") << 0 << -1 << QString() << QString(); } void tst_QXmppResultSet::testQuery() { QFETCH(QByteArray, xml); QFETCH(int, max); QFETCH(int, index); QFETCH(QString, before); QFETCH(QString, after); QXmppResultSetQuery iq; parsePacket(iq, xml); QCOMPARE(iq.max(), max); QCOMPARE(iq.index(), index); QCOMPARE(iq.before(), before); QCOMPARE(iq.before().isNull(), before.isNull()); QCOMPARE(iq.after(), after); QCOMPARE(iq.after().isNull(), after.isNull()); serializePacket(iq, xml); } void tst_QXmppResultSet::testReply_data() { QTest::addColumn("xml"); QTest::addColumn("count"); QTest::addColumn("index"); QTest::addColumn("first"); QTest::addColumn("last"); QTest::newRow("Example 4") << QByteArray( "" "stpeter@jabber.org" "peterpan@neverland.lit" "800" "") << 800 << 0 << QString("stpeter@jabber.org") << QString("peterpan@neverland.lit"); QTest::newRow("Example 6") << QByteArray( "" "stpeter@jabber.org" "peterpan@neverland.lit" "800" "") << 800 << 0 << QString("stpeter@jabber.org") << QString("peterpan@neverland.lit"); QTest::newRow("Example 4") << QByteArray( "" "peter@pixyland.org" "peter@rabbit.lit" "800" "") << 800 << 10 << QString("peter@pixyland.org") << QString("peter@rabbit.lit"); QTest::newRow("Example 7") << QByteArray( "" "790" "") << 790 << -1 << QString() << QString(); } void tst_QXmppResultSet::testReply() { QFETCH(QByteArray, xml); QFETCH(int, count); QFETCH(int, index); QFETCH(QString, first); QFETCH(QString, last); QXmppResultSetReply iq; parsePacket(iq, xml); QCOMPARE(iq.count(), count); QCOMPARE(iq.index(), index); QCOMPARE(iq.first(), first); QCOMPARE(iq.first().isNull(), first.isNull()); QCOMPARE(iq.last(), last); QCOMPARE(iq.last().isNull(), last.isNull()); serializePacket(iq, xml); } QTEST_MAIN(tst_QXmppResultSet) #include "tst_qxmppresultset.moc" qxmpp-0.9.3/tests/qxmpprosteriq/000077500000000000000000000000001263006255200167715ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmpprosteriq/qxmpprosteriq.pro000066400000000000000000000001221263006255200224440ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmpprosteriq SOURCES += tst_qxmpprosteriq.cpp qxmpp-0.9.3/tests/qxmpprosteriq/tst_qxmpprosteriq.cpp000066400000000000000000000052601263006255200233300ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppRosterIq.h" #include "util.h" class tst_QXmppRosterIq : public QObject { Q_OBJECT private slots: void testItem_data(); void testItem(); }; void tst_QXmppRosterIq::testItem_data() { QTest::addColumn("xml"); QTest::addColumn("name"); QTest::addColumn("subscriptionType"); QTest::newRow("none") << QByteArray("") << "" << int(QXmppRosterIq::Item::None); QTest::newRow("from") << QByteArray("") << "" << int(QXmppRosterIq::Item::From); QTest::newRow("to") << QByteArray("") << "" << int(QXmppRosterIq::Item::To); QTest::newRow("both") << QByteArray("") << "" << int(QXmppRosterIq::Item::Both); QTest::newRow("remove") << QByteArray("") << "" << int(QXmppRosterIq::Item::Remove); QTest::newRow("notset") << QByteArray("") << "" << int(QXmppRosterIq::Item::NotSet); QTest::newRow("name") << QByteArray("") << "foo bar" << int(QXmppRosterIq::Item::NotSet); } void tst_QXmppRosterIq::testItem() { QFETCH(QByteArray, xml); QFETCH(QString, name); QFETCH(int, subscriptionType); QXmppRosterIq::Item item; parsePacket(item, xml); QCOMPARE(item.bareJid(), QLatin1String("foo@example.com")); QCOMPARE(item.groups(), QSet()); QCOMPARE(item.name(), name); QCOMPARE(int(item.subscriptionType()), subscriptionType); QCOMPARE(item.subscriptionStatus(), QString()); serializePacket(item, xml); } QTEST_MAIN(tst_QXmppRosterIq) #include "tst_qxmpprosteriq.moc" qxmpp-0.9.3/tests/qxmpprpciq/000077500000000000000000000000001263006255200162375ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmpprpciq/qxmpprpciq.pro000066400000000000000000000001141263006255200211610ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmpprpciq SOURCES += tst_qxmpprpciq.cpp qxmpp-0.9.3/tests/qxmpprpciq/tst_qxmpprpciq.cpp000066400000000000000000000146511263006255200220500ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppRpcIq.h" #include "util.h" static void checkVariant(const QVariant &value, const QByteArray &xml) { // serialise QBuffer buffer; buffer.open(QIODevice::ReadWrite); QXmlStreamWriter writer(&buffer); QXmppRpcMarshaller::marshall(&writer, value); qDebug() << "expect " << xml; qDebug() << "writing" << buffer.data(); QCOMPARE(buffer.data(), xml); // parse QDomDocument doc; QCOMPARE(doc.setContent(xml, true), true); QDomElement element = doc.documentElement(); QStringList errors; QVariant test = QXmppRpcMarshaller::demarshall(element, errors); if (!errors.isEmpty()) qDebug() << errors; QCOMPARE(errors, QStringList()); QCOMPARE(test, value); } class tst_QXmppRpcIq : public QObject { Q_OBJECT private slots: void testBase64(); void testBool(); void testDateTime(); void testDouble(); void testInt(); void testNil(); void testString(); void testArray(); void testStruct(); void testInvoke(); void testResponse(); void testResponseFault(); }; void tst_QXmppRpcIq::testBase64() { checkVariant(QByteArray("\0\1\2\3", 4), QByteArray("AAECAw==")); } void tst_QXmppRpcIq::testBool() { checkVariant(false, QByteArray("0")); checkVariant(true, QByteArray("1")); } void tst_QXmppRpcIq::testDateTime() { checkVariant(QDateTime(QDate(1998, 7, 17), QTime(14, 8, 55)), QByteArray("1998-07-17T14:08:55")); } void tst_QXmppRpcIq::testDouble() { checkVariant(double(-12.214), QByteArray("-12.214")); } void tst_QXmppRpcIq::testInt() { checkVariant(int(-12), QByteArray("-12")); } void tst_QXmppRpcIq::testNil() { checkVariant(QVariant(), QByteArray("")); } void tst_QXmppRpcIq::testString() { checkVariant(QString("hello world"), QByteArray("hello world")); } void tst_QXmppRpcIq::testArray() { checkVariant(QVariantList() << QString("hello world") << double(-12.214), QByteArray("" "hello world" "-12.214" "")); } void tst_QXmppRpcIq::testStruct() { QMap map; map["bar"] = QString("hello world"); map["foo"] = double(-12.214); checkVariant(map, QByteArray("" "" "bar" "hello world" "" "" "foo" "-12.214" "" "")); } void tst_QXmppRpcIq::testInvoke() { const QByteArray xml( "" "" "" "examples.getStateName" "" "" "6" "" "" "" "" ""); QXmppRpcInvokeIq iq; parsePacket(iq, xml); QCOMPARE(iq.method(), QLatin1String("examples.getStateName")); QCOMPARE(iq.arguments(), QVariantList() << int(6)); serializePacket(iq, xml); } void tst_QXmppRpcIq::testResponse() { const QByteArray xml( "" "" "" "" "" "Colorado" "" "" "" "" ""); QXmppRpcResponseIq iq; parsePacket(iq, xml); QCOMPARE(iq.faultCode(), 0); QCOMPARE(iq.faultString(), QString()); QCOMPARE(iq.values(), QVariantList() << QString("Colorado")); serializePacket(iq, xml); } void tst_QXmppRpcIq::testResponseFault() { const QByteArray xml( "" "" "" "" "" "" "" "faultCode" "404" "" "" "faultString" "Not found" "" "" "" "" "" "" ""); QXmppRpcResponseIq iq; parsePacket(iq, xml); QCOMPARE(iq.faultCode(), 404); QCOMPARE(iq.faultString(), QLatin1String("Not found")); QCOMPARE(iq.values(), QVariantList()); serializePacket(iq, xml); } QTEST_MAIN(tst_QXmppRpcIq) #include "tst_qxmpprpciq.moc" qxmpp-0.9.3/tests/qxmpprtcppacket/000077500000000000000000000000001263006255200172615ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmpprtcppacket/qxmpprtcppacket.pro000066400000000000000000000001261263006255200232300ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmpprtcppacket SOURCES += tst_qxmpprtcppacket.cpp qxmpp-0.9.3/tests/qxmpprtcppacket/tst_qxmpprtcppacket.cpp000066400000000000000000000164361263006255200241170ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppRtcpPacket.h" class tst_QXmppRtcpPacket : public QObject { Q_OBJECT private slots: void testBad(); void testGoodbye(); void testGoodbyeWithReason(); void testReceiverReport(); void testSenderReport(); void testSenderReportWithReceiverReport(); void testSourceDescription(); }; void tst_QXmppRtcpPacket::testBad() { QXmppRtcpPacket packet; // too short QCOMPARE(packet.decode(QByteArray()), false); } void tst_QXmppRtcpPacket::testGoodbye() { const QByteArray data = QByteArray::fromHex("81cb000133425619"); QXmppRtcpPacket packet; QVERIFY(packet.decode(data)); QCOMPARE(packet.goodbyeReason(), QString()); QCOMPARE(packet.goodbyeSsrcs().size(), 1); QCOMPARE(packet.goodbyeSsrcs()[0], quint32(859985433)); QCOMPARE(packet.receiverReports().size(), 0); QCOMPARE(packet.senderInfo().ntpStamp(), quint64(0)); QCOMPARE(packet.senderInfo().octetCount(), quint32(0)); QCOMPARE(packet.senderInfo().packetCount(), quint32(0)); QCOMPARE(packet.senderInfo().rtpStamp(), quint32(0)); QCOMPARE(packet.sourceDescriptions().size(), 0); QCOMPARE(packet.ssrc(), quint32(0)); QCOMPARE(packet.type(), quint8(QXmppRtcpPacket::Goodbye)); QCOMPARE(packet.encode(), data); } void tst_QXmppRtcpPacket::testGoodbyeWithReason() { const QByteArray data = QByteArray::fromHex("81cb0003334256190462796521000000"); QXmppRtcpPacket packet; QVERIFY(packet.decode(data)); QCOMPARE(packet.goodbyeReason(), QLatin1String("bye!")); QCOMPARE(packet.goodbyeSsrcs().size(), 1); QCOMPARE(packet.goodbyeSsrcs()[0], quint32(859985433)); QCOMPARE(packet.receiverReports().size(), 0); QCOMPARE(packet.senderInfo().ntpStamp(), quint64(0)); QCOMPARE(packet.senderInfo().octetCount(), quint32(0)); QCOMPARE(packet.senderInfo().packetCount(), quint32(0)); QCOMPARE(packet.senderInfo().rtpStamp(), quint32(0)); QCOMPARE(packet.sourceDescriptions().size(), 0); QCOMPARE(packet.ssrc(), quint32(0)); QCOMPARE(packet.type(), quint8(QXmppRtcpPacket::Goodbye)); QCOMPARE(packet.encode(), data); } void tst_QXmppRtcpPacket::testReceiverReport() { const QByteArray data = QByteArray::fromHex("81c9000741f3bca22886dfa00000000000005eb90000001000000000fffbdae2"); QXmppRtcpPacket packet; QVERIFY(packet.decode(data)); QCOMPARE(packet.goodbyeReason(), QString()); QCOMPARE(packet.goodbyeSsrcs().size(), 0); QCOMPARE(packet.receiverReports().size(), 1); QCOMPARE(packet.receiverReports()[0].dlsr(), quint32(4294695650)); QCOMPARE(packet.receiverReports()[0].fractionLost(), quint8(0)); QCOMPARE(packet.receiverReports()[0].jitter(), quint32(16)); QCOMPARE(packet.receiverReports()[0].lsr(), quint32(0)); QCOMPARE(packet.receiverReports()[0].ssrc(), quint32(679927712)); QCOMPARE(packet.receiverReports()[0].totalLost(), quint32(0)); QCOMPARE(packet.senderInfo().ntpStamp(), quint64(0)); QCOMPARE(packet.senderInfo().octetCount(), quint32(0)); QCOMPARE(packet.senderInfo().packetCount(), quint32(0)); QCOMPARE(packet.senderInfo().rtpStamp(), quint32(0)); QCOMPARE(packet.sourceDescriptions().size(), 0); QCOMPARE(packet.ssrc(), quint32(1106492578)); QCOMPARE(packet.type(), quint8(QXmppRtcpPacket::ReceiverReport)); QCOMPARE(packet.encode(), data); } void tst_QXmppRtcpPacket::testSenderReport() { const QByteArray data = QByteArray::fromHex("80c8000627a6e4c1d97fec7d92acd9e8dd9e32570000007400004880"); QXmppRtcpPacket packet; QVERIFY(packet.decode(data)); QCOMPARE(packet.goodbyeReason(), QString()); QCOMPARE(packet.goodbyeSsrcs().size(), 0); QCOMPARE(packet.receiverReports().size(), 0); QCOMPARE(packet.senderInfo().ntpStamp(), quint64(15672505252348484072ULL)); QCOMPARE(packet.senderInfo().octetCount(), quint32(18560)); QCOMPARE(packet.senderInfo().packetCount(), quint32(116)); QCOMPARE(packet.senderInfo().rtpStamp(), quint32(3718132311)); QCOMPARE(packet.ssrc(), quint32(665248961)); QCOMPARE(packet.type(), quint8(QXmppRtcpPacket::SenderReport)); QCOMPARE(packet.sourceDescriptions().size(), 0); QCOMPARE(packet.encode(), data); } void tst_QXmppRtcpPacket::testSenderReportWithReceiverReport() { const QByteArray data = QByteArray::fromHex("81c8000c3efeb4decf80b8156fd6542c0000014000000003000001e081bc22520000000000007db50000002500000000fffbd605"); QXmppRtcpPacket packet; QVERIFY(packet.decode(data)); QCOMPARE(packet.goodbyeReason(), QString()); QCOMPARE(packet.goodbyeSsrcs().size(), 0); QCOMPARE(packet.receiverReports().size(), 1); QCOMPARE(packet.receiverReports()[0].dlsr(), quint32(4294694405)); QCOMPARE(packet.receiverReports()[0].fractionLost(), quint8(0)); QCOMPARE(packet.receiverReports()[0].jitter(), quint32(37)); QCOMPARE(packet.receiverReports()[0].lsr(), quint32(0)); QCOMPARE(packet.receiverReports()[0].ssrc(), quint32(2176590418)); QCOMPARE(packet.receiverReports()[0].totalLost(), quint32(0)); QCOMPARE(packet.senderInfo().ntpStamp(), quint64(14952153165080187948ULL)); QCOMPARE(packet.senderInfo().octetCount(), quint32(480)); QCOMPARE(packet.senderInfo().packetCount(), quint32(3)); QCOMPARE(packet.senderInfo().rtpStamp(), quint32(320)); QCOMPARE(packet.sourceDescriptions().size(), 0); QCOMPARE(packet.ssrc(), quint32(1056879838)); QCOMPARE(packet.type(), quint8(QXmppRtcpPacket::SenderReport)); QCOMPARE(packet.encode(), data); } void tst_QXmppRtcpPacket::testSourceDescription() { const QByteArray data = QByteArray::fromHex("81ca000c27a6e4c101267b64303361376334382d643930362d346239612d393832302d3131313830326463643537387d00000000"); QXmppRtcpPacket packet; QVERIFY(packet.decode(data)); QCOMPARE(packet.goodbyeReason(), QString()); QCOMPARE(packet.goodbyeSsrcs().size(), 0); QCOMPARE(packet.receiverReports().size(), 0); QCOMPARE(packet.senderInfo().ntpStamp(), quint64(0)); QCOMPARE(packet.senderInfo().octetCount(), quint32(0)); QCOMPARE(packet.senderInfo().packetCount(), quint32(0)); QCOMPARE(packet.senderInfo().rtpStamp(), quint32(0)); QCOMPARE(packet.sourceDescriptions().size(), 1); QCOMPARE(packet.sourceDescriptions()[0].cname(), QLatin1String("{d03a7c48-d906-4b9a-9820-111802dcd578}")); QCOMPARE(packet.sourceDescriptions()[0].name(), QString()); QCOMPARE(packet.sourceDescriptions()[0].ssrc(), quint32(665248961)); QCOMPARE(packet.ssrc(), quint32(0)); QCOMPARE(packet.type(), quint8(QXmppRtcpPacket::SourceDescription)); QCOMPARE(packet.encode(), data); } QTEST_MAIN(tst_QXmppRtcpPacket) #include "tst_qxmpprtcppacket.moc" qxmpp-0.9.3/tests/qxmpprtppacket/000077500000000000000000000000001263006255200171165ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmpprtppacket/qxmpprtppacket.pro000066400000000000000000000001241263006255200227200ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmpprtppacket SOURCES += tst_qxmpprtppacket.cpp qxmpp-0.9.3/tests/qxmpprtppacket/tst_qxmpprtppacket.cpp000066400000000000000000000051201263006255200235750ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppRtpPacket.h" class tst_QXmppRtpPacket : public QObject { Q_OBJECT private slots: void testBad(); void testSimple(); void testWithCsrc(); }; void tst_QXmppRtpPacket::testBad() { QXmppRtpPacket packet; // too short QCOMPARE(packet.decode(QByteArray()), false); QCOMPARE(packet.decode(QByteArray("\x80\x00\x3e", 3)), false); QCOMPARE(packet.decode(QByteArray("\x84\x00\x3e\xd2\x00\x00\x00\x90\x5f\xbd\x16\x9e", 12)), false); // wrong RTP version QCOMPARE(packet.decode(QByteArray("\x40\x00\x3e\xd2\x00\x00\x00\x90\x5f\xbd\x16\x9e", 12)), false); } void tst_QXmppRtpPacket::testSimple() { QByteArray data("\x80\x00\x3e\xd2\x00\x00\x00\x90\x5f\xbd\x16\x9e\x12\x34\x56", 15); QXmppRtpPacket packet; QCOMPARE(packet.decode(data), true); QCOMPARE(packet.marker(), false); QCOMPARE(packet.type(), quint8(0)); QCOMPARE(packet.sequence(), quint16(16082)); QCOMPARE(packet.stamp(), quint32(144)); QCOMPARE(packet.ssrc(), quint32(1606227614)); QCOMPARE(packet.csrc(), QList()); QCOMPARE(packet.payload(), QByteArray("\x12\x34\x56", 3)); QCOMPARE(packet.encode(), data); } void tst_QXmppRtpPacket::testWithCsrc() { QByteArray data("\x84\x00\x3e\xd2\x00\x00\x00\x90\x5f\xbd\x16\x9e\xab\xcd\xef\x01\xde\xad\xbe\xef\x12\x34\x56", 23); QXmppRtpPacket packet; QCOMPARE(packet.decode(data), true); QCOMPARE(packet.marker(), false); QCOMPARE(packet.type(), quint8(0)); QCOMPARE(packet.sequence(), quint16(16082)); QCOMPARE(packet.stamp(), quint32(144)); QCOMPARE(packet.ssrc(), quint32(1606227614)); QCOMPARE(packet.csrc(), QList() << quint32(0xabcdef01) << quint32(0xdeadbeef)); QCOMPARE(packet.payload(), QByteArray("\x12\x34\x56", 3)); QCOMPARE(packet.encode(), data); } QTEST_MAIN(tst_QXmppRtpPacket) #include "tst_qxmpprtppacket.moc" qxmpp-0.9.3/tests/qxmppsasl/000077500000000000000000000000001263006255200160635ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppsasl/qxmppsasl.pro000066400000000000000000000001121263006255200206270ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppsasl SOURCES += tst_qxmppsasl.cpp qxmpp-0.9.3/tests/qxmppsasl/tst_qxmppsasl.cpp000066400000000000000000000332501263006255200215140ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppSasl_p.h" #include "util.h" class tst_QXmppSasl : public QObject { Q_OBJECT private slots: void testParsing(); void testAuth_data(); void testAuth(); void testChallenge_data(); void testChallenge(); void testFailure(); void testResponse_data(); void testResponse(); void testSuccess(); // client void testClientAvailableMechanisms(); void testClientBadMechanism(); void testClientAnonymous(); void testClientDigestMd5(); void testClientDigestMd5_data(); void testClientFacebook(); void testClientGoogle(); void testClientPlain(); void testClientWindowsLive(); // server void testServerBadMechanism(); void testServerAnonymous(); void testServerDigestMd5(); void testServerPlain(); void testServerPlainChallenge(); }; void tst_QXmppSasl::testParsing() { // empty QMap empty = QXmppSaslDigestMd5::parseMessage(QByteArray()); QCOMPARE(empty.size(), 0); QCOMPARE(QXmppSaslDigestMd5::serializeMessage(empty), QByteArray()); // non-empty const QByteArray bytes("number=12345,quoted_plain=\"quoted string\",quoted_quote=\"quoted\\\\slash\\\"quote\",string=string"); QMap map = QXmppSaslDigestMd5::parseMessage(bytes); QCOMPARE(map.size(), 4); QCOMPARE(map["number"], QByteArray("12345")); QCOMPARE(map["quoted_plain"], QByteArray("quoted string")); QCOMPARE(map["quoted_quote"], QByteArray("quoted\\slash\"quote")); QCOMPARE(map["string"], QByteArray("string")); QCOMPARE(QXmppSaslDigestMd5::serializeMessage(map), bytes); } void tst_QXmppSasl::testAuth_data() { QTest::addColumn("xml"); QTest::addColumn("mechanism"); QTest::addColumn("value"); QTest::newRow("plain") << QByteArray("AGZvbwBiYXI=") << "PLAIN" << QByteArray("\0foo\0bar", 8); QTest::newRow("digest-md5") << QByteArray("") << "DIGEST-MD5" << QByteArray(); } void tst_QXmppSasl::testAuth() { QFETCH(QByteArray, xml); QFETCH(QString, mechanism); QFETCH(QByteArray, value); // no condition QXmppSaslAuth auth; parsePacket(auth, xml); QCOMPARE(auth.mechanism(), mechanism); QCOMPARE(auth.value(), value); serializePacket(auth, xml); } void tst_QXmppSasl::testChallenge_data() { QTest::addColumn("xml"); QTest::addColumn("value"); QTest::newRow("empty") << QByteArray("") << QByteArray(); QTest::newRow("value") << QByteArray("AGZvbwBiYXI=") << QByteArray("\0foo\0bar", 8); } void tst_QXmppSasl::testChallenge() { QFETCH(QByteArray, xml); QFETCH(QByteArray, value); // no condition QXmppSaslChallenge challenge; parsePacket(challenge, xml); QCOMPARE(challenge.value(), value); serializePacket(challenge, xml); } void tst_QXmppSasl::testFailure() { // no condition const QByteArray xml = ""; QXmppSaslFailure failure; parsePacket(failure, xml); QCOMPARE(failure.condition(), QString()); serializePacket(failure, xml); // not authorized const QByteArray xml2 = ""; QXmppSaslFailure failure2; parsePacket(failure2, xml2); QCOMPARE(failure2.condition(), QLatin1String("not-authorized")); serializePacket(failure2, xml2); } void tst_QXmppSasl::testResponse_data() { QTest::addColumn("xml"); QTest::addColumn("value"); QTest::newRow("empty") << QByteArray("") << QByteArray(); QTest::newRow("value") << QByteArray("AGZvbwBiYXI=") << QByteArray("\0foo\0bar", 8); } void tst_QXmppSasl::testResponse() { QFETCH(QByteArray, xml); QFETCH(QByteArray, value); // no condition QXmppSaslResponse response; parsePacket(response, xml); QCOMPARE(response.value(), value); serializePacket(response, xml); } void tst_QXmppSasl::testSuccess() { const QByteArray xml = ""; QXmppSaslSuccess stanza; parsePacket(stanza, xml); serializePacket(stanza, xml); } void tst_QXmppSasl::testClientAvailableMechanisms() { QCOMPARE(QXmppSaslClient::availableMechanisms(), QStringList() << "PLAIN" << "DIGEST-MD5" << "ANONYMOUS" << "X-FACEBOOK-PLATFORM" << "X-MESSENGER-OAUTH2" << "X-OAUTH2"); } void tst_QXmppSasl::testClientBadMechanism() { QXmppSaslClient *client = QXmppSaslClient::create("BAD-MECH"); QVERIFY(client == 0); } void tst_QXmppSasl::testClientAnonymous() { QXmppSaslClient *client = QXmppSaslClient::create("ANONYMOUS"); QVERIFY(client != 0); QCOMPARE(client->mechanism(), QLatin1String("ANONYMOUS")); // initial step returns nothing QByteArray response; QVERIFY(client->respond(QByteArray(), response)); QCOMPARE(response, QByteArray()); // any further step is an error QVERIFY(!client->respond(QByteArray(), response)); delete client; } void tst_QXmppSasl::testClientDigestMd5_data() { QTest::addColumn("qop"); QTest::newRow("qop-none") << QByteArray(); QTest::newRow("qop-auth") << QByteArray(",qop=\"auth\""); QTest::newRow("qop-multi") << QByteArray(",qop=\"auth,auth-int\""); } void tst_QXmppSasl::testClientDigestMd5() { QFETCH(QByteArray, qop); QXmppSaslDigestMd5::setNonce("AMzVG8Oibf+sVUCPPlWLR8lZQvbbJtJB9vJd+u3c6dw="); QXmppSaslClient *client = QXmppSaslClient::create("DIGEST-MD5"); QVERIFY(client != 0); QCOMPARE(client->mechanism(), QLatin1String("DIGEST-MD5")); client->setUsername("qxmpp1"); client->setPassword("qxmpp123"); client->setHost("jabber.ru"); client->setServiceType("xmpp"); // initial step returns nothing QByteArray response; QVERIFY(client->respond(QByteArray(), response)); QCOMPARE(response, QByteArray()); QVERIFY(client->respond(QByteArray("nonce=\"2530347127\"") + qop + QByteArray("charset=utf-8,algorithm=md5-sess"), response)); QCOMPARE(response, QByteArray("charset=utf-8,cnonce=\"AMzVG8Oibf+sVUCPPlWLR8lZQvbbJtJB9vJd+u3c6dw=\",digest-uri=\"xmpp/jabber.ru\",nc=00000001,nonce=2530347127,qop=auth,response=a61fbf4320577d74038b71a8546bc7ae,username=qxmpp1")); QVERIFY(client->respond(QByteArray("rspauth=d92bf7f4331700c24799cbab364a14b7"), response)); QCOMPARE(response, QByteArray()); // any further step is an error QVERIFY(!client->respond(QByteArray(), response)); delete client; } void tst_QXmppSasl::testClientFacebook() { QXmppSaslClient *client = QXmppSaslClient::create("X-FACEBOOK-PLATFORM"); QVERIFY(client != 0); QCOMPARE(client->mechanism(), QLatin1String("X-FACEBOOK-PLATFORM")); client->setUsername("123456789012345"); client->setPassword("abcdefghijlkmno"); // initial step returns nothing QByteArray response; QVERIFY(client->respond(QByteArray(), response)); QCOMPARE(response, QByteArray()); // challenge response QVERIFY(client->respond(QByteArray("version=1&method=auth.xmpp_login&nonce=AA4EFEE16F2AB64B131EEFFE6EACDDB8"), response)); QCOMPARE(response, QByteArray("access_token=abcdefghijlkmno&api_key=123456789012345&call_id=&method=auth.xmpp_login&nonce=AA4EFEE16F2AB64B131EEFFE6EACDDB8&v=1.0")); // any further step is an error QVERIFY(!client->respond(QByteArray(), response)); delete client; } void tst_QXmppSasl::testClientGoogle() { QXmppSaslClient *client = QXmppSaslClient::create("X-OAUTH2"); QVERIFY(client != 0); QCOMPARE(client->mechanism(), QLatin1String("X-OAUTH2")); client->setUsername("foo"); client->setPassword("bar"); // initial step returns data QByteArray response; QVERIFY(client->respond(QByteArray(), response)); QCOMPARE(response, QByteArray("\0foo\0bar", 8)); // any further step is an error QVERIFY(!client->respond(QByteArray(), response)); delete client; } void tst_QXmppSasl::testClientPlain() { QXmppSaslClient *client = QXmppSaslClient::create("PLAIN"); QVERIFY(client != 0); QCOMPARE(client->mechanism(), QLatin1String("PLAIN")); client->setUsername("foo"); client->setPassword("bar"); // initial step returns data QByteArray response; QVERIFY(client->respond(QByteArray(), response)); QCOMPARE(response, QByteArray("\0foo\0bar", 8)); // any further step is an error QVERIFY(!client->respond(QByteArray(), response)); delete client; } void tst_QXmppSasl::testClientWindowsLive() { QXmppSaslClient *client = QXmppSaslClient::create("X-MESSENGER-OAUTH2"); QVERIFY(client != 0); QCOMPARE(client->mechanism(), QLatin1String("X-MESSENGER-OAUTH2")); client->setPassword(QByteArray("footoken").toBase64()); // initial step returns data QByteArray response; QVERIFY(client->respond(QByteArray(), response)); QCOMPARE(response, QByteArray("footoken", 8)); // any further step is an error QVERIFY(!client->respond(QByteArray(), response)); delete client; } void tst_QXmppSasl::testServerBadMechanism() { QXmppSaslServer *server = QXmppSaslServer::create("BAD-MECH"); QVERIFY(server == 0); } void tst_QXmppSasl::testServerAnonymous() { QXmppSaslServer *server = QXmppSaslServer::create("ANONYMOUS"); QVERIFY(server != 0); QCOMPARE(server->mechanism(), QLatin1String("ANONYMOUS")); // initial step returns success QByteArray response; QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Succeeded); QCOMPARE(response, QByteArray()); // any further step is an error QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Failed); delete server; } void tst_QXmppSasl::testServerDigestMd5() { QXmppSaslDigestMd5::setNonce("OI08/m+QRm6Ma+fKOjuqVXtz40sR5u9/u5GN6sSW0rs="); QXmppSaslServer *server = QXmppSaslServer::create("DIGEST-MD5"); QVERIFY(server != 0); QCOMPARE(server->mechanism(), QLatin1String("DIGEST-MD5")); // initial step returns challenge QByteArray response; QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Challenge); QCOMPARE(response, QByteArray("algorithm=md5-sess,charset=utf-8,nonce=\"OI08/m+QRm6Ma+fKOjuqVXtz40sR5u9/u5GN6sSW0rs=\",qop=auth")); // password needed const QByteArray request = QByteArray("charset=utf-8,cnonce=\"AMzVG8Oibf+sVUCPPlWLR8lZQvbbJtJB9vJd+u3c6dw=\",digest-uri=\"xmpp/jabber.ru\",nc=00000001,nonce=\"OI08/m+QRm6Ma+fKOjuqVXtz40sR5u9/u5GN6sSW0rs=\",qop=auth,response=70e9063257ee2bf6bfd108975b917410,username=qxmpp1"); QCOMPARE(server->respond(request, response), QXmppSaslServer::InputNeeded); QCOMPARE(server->username(), QLatin1String("qxmpp1")); server->setPassword("qxmpp123"); // second challenge QCOMPARE(server->respond(request, response), QXmppSaslServer::Challenge); QCOMPARE(response, QByteArray("rspauth=2821a3add271b9ae02b813bed57ec878")); // success QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Succeeded); QCOMPARE(response, QByteArray()); // any further step is an error QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Failed); delete server; } void tst_QXmppSasl::testServerPlain() { QXmppSaslServer *server = QXmppSaslServer::create("PLAIN"); QVERIFY(server != 0); QCOMPARE(server->mechanism(), QLatin1String("PLAIN")); // initial step returns success QByteArray response; QCOMPARE(server->respond(QByteArray("\0foo\0bar", 8), response), QXmppSaslServer::InputNeeded); QCOMPARE(response, QByteArray()); QCOMPARE(server->username(), QLatin1String("foo")); QCOMPARE(server->password(), QLatin1String("bar")); // any further step is an error QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Failed); delete server; } void tst_QXmppSasl::testServerPlainChallenge() { QXmppSaslServer *server = QXmppSaslServer::create("PLAIN"); QVERIFY(server != 0); QCOMPARE(server->mechanism(), QLatin1String("PLAIN")); // initial step returns challenge QByteArray response; QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Challenge); QCOMPARE(response, QByteArray()); // initial step returns success QCOMPARE(server->respond(QByteArray("\0foo\0bar", 8), response), QXmppSaslServer::InputNeeded); QCOMPARE(response, QByteArray()); QCOMPARE(server->username(), QLatin1String("foo")); QCOMPARE(server->password(), QLatin1String("bar")); // any further step is an error QCOMPARE(server->respond(QByteArray(), response), QXmppSaslServer::Failed); delete server; } QTEST_MAIN(tst_QXmppSasl) #include "tst_qxmppsasl.moc" qxmpp-0.9.3/tests/qxmppserver/000077500000000000000000000000001263006255200164275ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppserver/qxmppserver.pro000066400000000000000000000001161263006255200215430ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppserver SOURCES += tst_qxmppserver.cpp qxmpp-0.9.3/tests/qxmppserver/tst_qxmppserver.cpp000066400000000000000000000056751263006255200224360ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppClient.h" #include "QXmppServer.h" #include "util.h" class tst_QXmppServer : public QObject { Q_OBJECT private slots: void testConnect_data(); void testConnect(); }; void tst_QXmppServer::testConnect_data() { QTest::addColumn("username"); QTest::addColumn("password"); QTest::addColumn("mechanism"); QTest::addColumn("connected"); QTest::newRow("plain-good") << "testuser" << "testpwd" << "PLAIN" << true; QTest::newRow("plain-bad-username") << "baduser" << "testpwd" << "PLAIN" << false; QTest::newRow("plain-bad-password") << "testuser" << "badpwd" << "PLAIN" << false; QTest::newRow("digest-good") << "testuser" << "testpwd" << "DIGEST-MD5" << true; QTest::newRow("digest-bad-username") << "baduser" << "testpwd" << "DIGEST-MD5" << false; QTest::newRow("digest-bad-password") << "testuser" << "badpwd" << "DIGEST-MD5" << false; } void tst_QXmppServer::testConnect() { QFETCH(QString, username); QFETCH(QString, password); QFETCH(QString, mechanism); QFETCH(bool, connected); const QString testDomain("localhost"); const QHostAddress testHost(QHostAddress::LocalHost); const quint16 testPort = 12345; QXmppLogger logger; //logger.setLoggingType(QXmppLogger::StdoutLogging); // prepare server TestPasswordChecker passwordChecker; passwordChecker.addCredentials("testuser", "testpwd"); QXmppServer server; server.setDomain(testDomain); server.setLogger(&logger); server.setPasswordChecker(&passwordChecker); server.listenForClients(testHost, testPort); // prepare client QXmppClient client; client.setLogger(&logger); QEventLoop loop; connect(&client, SIGNAL(connected()), &loop, SLOT(quit())); connect(&client, SIGNAL(disconnected()), &loop, SLOT(quit())); QXmppConfiguration config; config.setDomain(testDomain); config.setHost(testHost.toString()); config.setPort(testPort); config.setUser(username); config.setPassword(password); config.setSaslAuthMechanism(mechanism); client.connectToServer(config); loop.exec(); QCOMPARE(client.isConnected(), connected); } QTEST_MAIN(tst_QXmppServer) #include "tst_qxmppserver.moc" qxmpp-0.9.3/tests/qxmppsessioniq/000077500000000000000000000000001263006255200171365ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppsessioniq/qxmppsessioniq.pro000066400000000000000000000001241263006255200227600ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppsessioniq SOURCES += tst_qxmppsessioniq.cpp qxmpp-0.9.3/tests/qxmppsessioniq/tst_qxmppsessioniq.cpp000066400000000000000000000025501263006255200236410ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppSessionIq.h" #include "util.h" class TestPackets : public QObject { Q_OBJECT private slots: void testSession(); }; void TestPackets::testSession() { const QByteArray xml( "" "" ""); QXmppSessionIq session; parsePacket(session, xml); QCOMPARE(session.id(), QString("session_1")); QCOMPARE(session.to(), QString("example.com")); QCOMPARE(session.type(), QXmppIq::Set); serializePacket(session, xml); } QTEST_MAIN(TestPackets) #include "tst_qxmppsessioniq.moc" qxmpp-0.9.3/tests/qxmppsocks/000077500000000000000000000000001263006255200162435ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppsocks/qxmppsocks.pro000066400000000000000000000001141263006255200211710ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppsocks SOURCES += tst_qxmppsocks.cpp qxmpp-0.9.3/tests/qxmppsocks/tst_qxmppsocks.cpp000066400000000000000000000220511263006255200220510ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppSocks.h" #include "util.h" class tst_QXmppSocks : public QObject { Q_OBJECT private slots: void init(); void newConnectionSlot(QTcpSocket *socket, QString hostName, quint16 port); void testClient_data(); void testClient(); void testClientAndServer(); void testServer_data(); void testServer(); private: QTcpSocket *m_connectionSocket; QString m_connectionHostName; quint16 m_connectionPort; }; void tst_QXmppSocks::init() { m_connectionSocket = 0; m_connectionHostName = QString(); m_connectionPort = 0; } void tst_QXmppSocks::newConnectionSlot(QTcpSocket *socket, QString hostName, quint16 port) { m_connectionSocket = socket; m_connectionHostName = hostName; m_connectionPort = port; } void tst_QXmppSocks::testClient_data() { QTest::addColumn("serverHandshake"); QTest::addColumn("serverHandshakeWorks"); QTest::addColumn("serverConnect"); QTest::addColumn("serverConnectWorks"); QTest::addColumn("clientReceivedData"); QTest::newRow("no authentication - good connect") << QByteArray::fromHex("0500") << true << QByteArray::fromHex("050000030e7777772e676f6f676c652e636f6d0050") << true << QByteArray(); QTest::newRow("no authentication - good connect and data") << QByteArray::fromHex("0500") << true << QByteArray::fromHex("050000030e7777772e676f6f676c652e636f6d0050001122") << true << QByteArray::fromHex("001122"); QTest::newRow("no authentication - bad connect") << QByteArray::fromHex("0500") << true << QByteArray::fromHex("0500") << false << QByteArray(); QTest::newRow("bad authentication") << QByteArray::fromHex("05ff") << false << QByteArray() << false << QByteArray(); } void tst_QXmppSocks::testClient() { QFETCH(QByteArray, serverHandshake); QFETCH(bool, serverHandshakeWorks); QFETCH(QByteArray, serverConnect); QFETCH(bool, serverConnectWorks); QFETCH(QByteArray, clientReceivedData); QTcpServer server; QVERIFY(server.listen()); QVERIFY(server.serverPort() != 0); QXmppSocksClient client("127.0.0.1", server.serverPort()); QEventLoop loop; connect(&server, SIGNAL(newConnection()), &loop, SLOT(quit())); client.connectToHost("www.google.com", 80); loop.exec(); // receive client handshake m_connectionSocket = server.nextPendingConnection(); QVERIFY(m_connectionSocket); connect(m_connectionSocket, SIGNAL(disconnected()), &loop, SLOT(quit())); connect(m_connectionSocket, SIGNAL(readyRead()), &loop, SLOT(quit())); loop.exec(); QCOMPARE(client.state(), QAbstractSocket::ConnectedState); QCOMPARE(m_connectionSocket->state(), QAbstractSocket::ConnectedState); QCOMPARE(m_connectionSocket->readAll(), QByteArray::fromHex("050100")); // receive client connect m_connectionSocket->write(serverHandshake); loop.exec(); if (!serverHandshakeWorks) { QCOMPARE(client.state(), QAbstractSocket::UnconnectedState); QCOMPARE(m_connectionSocket->state(), QAbstractSocket::UnconnectedState); return; } QCOMPARE(client.state(), QAbstractSocket::ConnectedState); QCOMPARE(m_connectionSocket->state(), QAbstractSocket::ConnectedState); QCOMPARE(m_connectionSocket->readAll(), QByteArray::fromHex("050100030e7777772e676f6f676c652e636f6d0050")); // wait for client to be ready connect(&client, SIGNAL(ready()), &loop, SLOT(quit())); m_connectionSocket->write(serverConnect); loop.exec(); if (!serverConnectWorks) { QCOMPARE(client.state(), QAbstractSocket::UnconnectedState); QCOMPARE(m_connectionSocket->state(), QAbstractSocket::UnconnectedState); return; } QCOMPARE(client.state(), QAbstractSocket::ConnectedState); QCOMPARE(m_connectionSocket->state(), QAbstractSocket::ConnectedState); QByteArray received = client.readAll(); QCOMPARE(received, clientReceivedData); // disconnect client.disconnectFromHost(); } void tst_QXmppSocks::testClientAndServer() { QXmppSocksServer server; QVERIFY(server.listen()); QVERIFY(server.serverPort() != 0); connect(&server, SIGNAL(newConnection(QTcpSocket*,QString,quint16)), this, SLOT(newConnectionSlot(QTcpSocket*,QString,quint16))); QXmppSocksClient client("127.0.0.1", server.serverPort()); QEventLoop loop; connect(&client, SIGNAL(ready()), &loop, SLOT(quit())); client.connectToHost("www.google.com", 80); loop.exec(); // check client QCOMPARE(client.state(), QAbstractSocket::ConnectedState); // check server QVERIFY(m_connectionSocket); QCOMPARE(m_connectionSocket->state(), QAbstractSocket::ConnectedState); QCOMPARE(m_connectionHostName, QLatin1String("www.google.com")); QCOMPARE(m_connectionPort, quint16(80)); // disconnect client.disconnectFromHost(); } void tst_QXmppSocks::testServer_data() { QTest::addColumn("clientHandshake"); QTest::addColumn("clientHandshakeWorks"); QTest::addColumn("clientConnect"); QTest::addColumn("clientConnectWorks"); QTest::newRow("no authentication - connect to www.google.com:80") << QByteArray::fromHex("050100") << true << QByteArray::fromHex("050100030e7777772e676f6f676c652e636f6d0050") << true; QTest::newRow("no authentication - bad connect") << QByteArray::fromHex("050100") << true << QByteArray::fromHex("0500") << false; QTest::newRow("no authentication or GSSAPI - connect to www.google.com:80") << QByteArray::fromHex("05020001") << true << QByteArray::fromHex("050100030e7777772e676f6f676c652e636f6d0050") << true; QTest::newRow("bad SOCKS version") << QByteArray::fromHex("060100") << false << QByteArray() << false; QTest::newRow("no methods") << QByteArray::fromHex("0500") << false << QByteArray() << false; QTest::newRow("GSSAPI only") << QByteArray::fromHex("050101") << false << QByteArray() << false; } void tst_QXmppSocks::testServer() { QFETCH(QByteArray, clientHandshake); QFETCH(bool, clientHandshakeWorks); QFETCH(QByteArray, clientConnect); QFETCH(bool, clientConnectWorks); QXmppSocksServer server; QVERIFY(server.listen()); QVERIFY(server.serverPort() != 0); connect(&server, SIGNAL(newConnection(QTcpSocket*,QString,quint16)), this, SLOT(newConnectionSlot(QTcpSocket*,QString,quint16))); QTcpSocket client; client.connectToHost(QHostAddress::LocalHost, server.serverPort()); QVERIFY2(client.waitForConnected(), qPrintable(client.errorString())); QEventLoop loop; connect(&client, SIGNAL(disconnected()), &loop, SLOT(quit())); connect(&client, SIGNAL(readyRead()), &loop, SLOT(quit())); // send client handshake client.write(clientHandshake); loop.exec(); if (!clientHandshakeWorks) { // consume any last data QByteArray data = client.readAll(); if (client.state() != QAbstractSocket::UnconnectedState) loop.exec(); QCOMPARE(client.state(), QAbstractSocket::UnconnectedState); QVERIFY(!m_connectionSocket); QVERIFY(m_connectionHostName.isNull()); QCOMPARE(m_connectionPort, quint16(0)); return; } QCOMPARE(client.state(), QAbstractSocket::ConnectedState); QCOMPARE(client.readAll(), QByteArray::fromHex("0500")); // request connect to www.google.com port 80 client.write(clientConnect); loop.exec(); if (!clientConnectWorks) { QCOMPARE(client.state(), QAbstractSocket::UnconnectedState); QVERIFY(!m_connectionSocket); QVERIFY(m_connectionHostName.isNull()); QCOMPARE(m_connectionPort, quint16(0)); return; } QCOMPARE(client.state(), QAbstractSocket::ConnectedState); QCOMPARE(client.readAll(), QByteArray::fromHex("050000030e7777772e676f6f676c652e636f6d0050")); QCOMPARE(client.state(), QAbstractSocket::ConnectedState); QVERIFY(m_connectionSocket); QCOMPARE(m_connectionSocket->state(), QAbstractSocket::ConnectedState); QCOMPARE(m_connectionHostName, QLatin1String("www.google.com")); QCOMPARE(m_connectionPort, quint16(80)); // disconnect client.disconnectFromHost(); } QTEST_MAIN(tst_QXmppSocks) #include "tst_qxmppsocks.moc" qxmpp-0.9.3/tests/qxmppstanza/000077500000000000000000000000001263006255200164215ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppstanza/qxmppstanza.pro000066400000000000000000000001161263006255200215270ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppstanza SOURCES += tst_qxmppstanza.cpp qxmpp-0.9.3/tests/qxmppstanza/tst_qxmppstanza.cpp000066400000000000000000000042211263006255200224040ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppStanza.h" #include "util.h" class tst_QXmppStanza : public QObject { Q_OBJECT private slots: void testExtendedAddress_data(); void testExtendedAddress(); }; void tst_QXmppStanza::testExtendedAddress_data() { QTest::addColumn("xml"); QTest::addColumn("delivered"); QTest::addColumn("description"); QTest::addColumn("jid"); QTest::addColumn("type"); QTest::newRow("simple") << QByteArray("
") << false << QString() << QString("foo@example.com/QXmpp") << QString("bcc"); QTest::newRow("full") << QByteArray("
") << true << QString("some description") << QString("foo@example.com/QXmpp") << QString("bcc"); } void tst_QXmppStanza::testExtendedAddress() { QFETCH(QByteArray, xml); QFETCH(bool, delivered); QFETCH(QString, description); QFETCH(QString, jid); QFETCH(QString, type); QXmppExtendedAddress address; parsePacket(address, xml); QCOMPARE(address.isDelivered(), delivered); QCOMPARE(address.description(), description); QCOMPARE(address.jid(), jid); QCOMPARE(address.type(), type); serializePacket(address, xml); } QTEST_MAIN(tst_QXmppStanza) #include "tst_qxmppstanza.moc" qxmpp-0.9.3/tests/qxmppstreamfeatures/000077500000000000000000000000001263006255200201535ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppstreamfeatures/qxmppstreamfeatures.pro000066400000000000000000000001361263006255200250150ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppstreamfeatures SOURCES += tst_qxmppstreamfeatures.cpp qxmpp-0.9.3/tests/qxmppstreamfeatures/tst_qxmppstreamfeatures.cpp000066400000000000000000000051331263006255200256730ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppStreamFeatures.h" #include "util.h" class tst_QXmppStreamFeatures : public QObject { Q_OBJECT private slots: void testEmpty(); void testFull(); }; void tst_QXmppStreamFeatures::testEmpty() { const QByteArray xml(""); QXmppStreamFeatures features; parsePacket(features, xml); QCOMPARE(features.bindMode(), QXmppStreamFeatures::Disabled); QCOMPARE(features.sessionMode(), QXmppStreamFeatures::Disabled); QCOMPARE(features.nonSaslAuthMode(), QXmppStreamFeatures::Disabled); QCOMPARE(features.tlsMode(), QXmppStreamFeatures::Disabled); QCOMPARE(features.authMechanisms(), QStringList()); QCOMPARE(features.compressionMethods(), QStringList()); serializePacket(features, xml); } void tst_QXmppStreamFeatures::testFull() { const QByteArray xml("" "" "" "" "" "zlib" "PLAIN" ""); QXmppStreamFeatures features; parsePacket(features, xml); QCOMPARE(features.bindMode(), QXmppStreamFeatures::Enabled); QCOMPARE(features.sessionMode(), QXmppStreamFeatures::Enabled); QCOMPARE(features.nonSaslAuthMode(), QXmppStreamFeatures::Enabled); QCOMPARE(features.tlsMode(), QXmppStreamFeatures::Enabled); QCOMPARE(features.authMechanisms(), QStringList() << "PLAIN"); QCOMPARE(features.compressionMethods(), QStringList() << "zlib"); serializePacket(features, xml); } QTEST_MAIN(tst_QXmppStreamFeatures) #include "tst_qxmppstreamfeatures.moc" qxmpp-0.9.3/tests/qxmppstreaminitiationiq/000077500000000000000000000000001263006255200210365ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppstreaminitiationiq/qxmppstreaminitiationiq.pro000066400000000000000000000001461263006255200265640ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppstreaminitiationiq SOURCES += tst_qxmppstreaminitiationiq.cpp qxmpp-0.9.3/tests/qxmppstreaminitiationiq/tst_qxmppstreaminitiationiq.cpp000066400000000000000000000111051263006255200274350ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Olivier Goffart * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppStreamInitiationIq_p.h" #include "QXmppTransferManager.h" #include "util.h" class tst_QXmppStreamInitiationIq : public QObject { Q_OBJECT private slots: void testFileInfo_data(); void testFileInfo(); void testOffer(); void testResult(); }; void tst_QXmppStreamInitiationIq::testFileInfo_data() { QTest::addColumn("xml"); QTest::addColumn("date"); QTest::addColumn("description"); QTest::addColumn("hash"); QTest::addColumn("name"); QTest::addColumn("size"); QTest::newRow("normal") << QByteArray("") << QDateTime() << QString() << QByteArray() << QString("test.txt") << qint64(1022); QTest::newRow("full") << QByteArray("" "This is a test. If this were a real file..." "") << QDateTime(QDate(1969, 7, 21), QTime(2, 56, 15), Qt::UTC) << QString("This is a test. If this were a real file...") << QByteArray::fromHex("552da749930852c69ae5d2141d3766b1") << QString("test.txt") << qint64(1022); } void tst_QXmppStreamInitiationIq::testFileInfo() { QFETCH(QByteArray, xml); QFETCH(QDateTime, date); QFETCH(QString, description); QFETCH(QByteArray, hash); QFETCH(QString, name); QFETCH(qint64, size); QXmppTransferFileInfo info; parsePacket(info, xml); QCOMPARE(info.date(), date); QCOMPARE(info.description(), description); QCOMPARE(info.hash(), hash); QCOMPARE(info.name(), name); QCOMPARE(info.size(), size); serializePacket(info, xml); } void tst_QXmppStreamInitiationIq::testOffer() { QByteArray xml( "" "" "" "" "" "" "" "" "" "" "" "" ""); QXmppStreamInitiationIq iq; parsePacket(iq, xml); QVERIFY(!iq.fileInfo().isNull()); QCOMPARE(iq.fileInfo().name(), QString("test.txt")); QCOMPARE(iq.fileInfo().size(), qint64(1022)); serializePacket(iq, xml); } void tst_QXmppStreamInitiationIq::testResult() { QByteArray xml( "" "" "" "" "" "http://jabber.org/protocol/bytestreams" "" "" "" "" ""); QXmppStreamInitiationIq iq; parsePacket(iq, xml); QVERIFY(iq.fileInfo().isNull()); serializePacket(iq, xml); } QTEST_MAIN(tst_QXmppStreamInitiationIq) #include "tst_qxmppstreaminitiationiq.moc" qxmpp-0.9.3/tests/qxmppstunmessage/000077500000000000000000000000001263006255200174575ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppstunmessage/qxmppstunmessage.pro000066400000000000000000000001301263006255200236170ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppstunmessage SOURCES += tst_qxmppstunmessage.cpp qxmpp-0.9.3/tests/qxmppstunmessage/tst_qxmppstunmessage.cpp000066400000000000000000000106121263006255200245010ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppStun.h" #include "util.h" class tst_QXmppStunMessage : public QObject { Q_OBJECT private slots: void testFingerprint(); void testIntegrity(); void testIPv4Address(); void testIPv6Address(); void testXorIPv4Address(); void testXorIPv6Address(); }; void tst_QXmppStunMessage::testFingerprint() { // without fingerprint QXmppStunMessage msg; msg.setType(0x0001); QCOMPARE(msg.encode(QByteArray(), false), QByteArray("\x00\x01\x00\x00\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 20)); // with fingerprint QCOMPARE(msg.encode(QByteArray(), true), QByteArray("\x00\x01\x00\x08\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x28\x00\x04\xB2\xAA\xF9\xF6", 28)); } void tst_QXmppStunMessage::testIntegrity() { QXmppStunMessage msg; msg.setType(0x0001); QCOMPARE(msg.encode(QByteArray("somesecret"), false), QByteArray("\x00\x01\x00\x18\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x14\x96\x4B\x40\xD1\x84\x67\x6A\xFD\xB5\xE0\x7C\xC5\x1F\xFB\xBD\xA2\x61\xAF\xB1\x26", 44)); } void tst_QXmppStunMessage::testIPv4Address() { // encode QXmppStunMessage msg; msg.setType(0x0001); msg.mappedHost = QHostAddress("127.0.0.1"); msg.mappedPort = 12345; QByteArray packet = msg.encode(QByteArray(), false); QCOMPARE(packet, QByteArray("\x00\x01\x00\x0C\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x08\x00\x01\x30\x39\x7F\x00\x00\x01", 32)); // decode QXmppStunMessage msg2; msg2.decode(packet); QCOMPARE(msg2.mappedHost, QHostAddress("127.0.0.1")); QCOMPARE(msg2.mappedPort, quint16(12345)); } void tst_QXmppStunMessage::testIPv6Address() { // encode QXmppStunMessage msg; msg.setType(0x0001); msg.mappedHost = QHostAddress("::1"); msg.mappedPort = 12345; const QByteArray packet = msg.encode(QByteArray(), false); QCOMPARE(packet, QByteArray("\x00\x01\x00\x18\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x14\x00\x02\x30\x39\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 44)); // decode QXmppStunMessage msg2; msg2.decode(packet); QCOMPARE(msg2.mappedHost, QHostAddress("::1")); QCOMPARE(msg2.mappedPort, quint16(12345)); } void tst_QXmppStunMessage::testXorIPv4Address() { // encode QXmppStunMessage msg; msg.setType(0x0001); msg.xorMappedHost = QHostAddress("127.0.0.1"); msg.xorMappedPort = 12345; QByteArray packet = msg.encode(QByteArray(), false); QCOMPARE(packet, QByteArray("\x00\x01\x00\x0C\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x08\x00\x01\x11\x2B\x5E\x12\xA4\x43", 32)); // decode QXmppStunMessage msg2; msg2.decode(packet); QCOMPARE(msg2.xorMappedHost, QHostAddress("127.0.0.1")); QCOMPARE(msg2.xorMappedPort, quint16(12345)); } void tst_QXmppStunMessage::testXorIPv6Address() { // encode QXmppStunMessage msg; msg.setType(0x0001); msg.xorMappedHost = QHostAddress("::1"); msg.xorMappedPort = 12345; const QByteArray packet = msg.encode(QByteArray(), false); QCOMPARE(packet, QByteArray("\x00\x01\x00\x18\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x14\x00\x02\x11\x2B\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 44)); // decode QXmppStunMessage msg2; msg2.decode(packet); QCOMPARE(msg2.xorMappedHost, QHostAddress("::1")); QCOMPARE(msg2.xorMappedPort, quint16(12345)); } QTEST_MAIN(tst_QXmppStunMessage) #include "tst_qxmppstunmessage.moc" qxmpp-0.9.3/tests/qxmpptransfermanager/000077500000000000000000000000001263006255200203005ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmpptransfermanager/qxmpptransfermanager.pro000066400000000000000000000002121263006255200252620ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmpptransfermanager RESOURCES += tst_qxmpptransfermanager.qrc SOURCES += tst_qxmpptransfermanager.cpp qxmpp-0.9.3/tests/qxmpptransfermanager/test.svg000066400000000000000000000043501263006255200220020ustar00rootroot00000000000000 image/svg+xml qxmpp-0.9.3/tests/qxmpptransfermanager/tst_qxmpptransfermanager.cpp000066400000000000000000000141661263006255200261530ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppClient.h" #include "QXmppServer.h" #include "QXmppTransferManager.h" #include "util.h" Q_DECLARE_METATYPE(QXmppTransferJob::Method) class tst_QXmppTransferManager : public QObject { Q_OBJECT private slots: void init(); void testSendFile_data(); void testSendFile(); void acceptFile(QXmppTransferJob *job); private: QBuffer receiverBuffer; QXmppTransferJob *receiverJob; }; void tst_QXmppTransferManager::init() { receiverBuffer.close(); receiverBuffer.setData(QByteArray()); receiverJob = 0; } void tst_QXmppTransferManager::acceptFile(QXmppTransferJob *job) { receiverJob = job; receiverBuffer.open(QIODevice::WriteOnly); job->accept(&receiverBuffer); } void tst_QXmppTransferManager::testSendFile_data() { QTest::addColumn("senderMethods"); QTest::addColumn("receiverMethods"); QTest::addColumn("works"); QTest::newRow("any - any") << QXmppTransferJob::AnyMethod << QXmppTransferJob::AnyMethod << true; QTest::newRow("any - inband") << QXmppTransferJob::AnyMethod << QXmppTransferJob::InBandMethod << true; QTest::newRow("any - socks") << QXmppTransferJob::AnyMethod << QXmppTransferJob::SocksMethod << true; QTest::newRow("inband - any") << QXmppTransferJob::InBandMethod << QXmppTransferJob::AnyMethod << true; QTest::newRow("inband - inband") << QXmppTransferJob::InBandMethod << QXmppTransferJob::InBandMethod << true; QTest::newRow("inband - socks") << QXmppTransferJob::InBandMethod << QXmppTransferJob::SocksMethod << false; QTest::newRow("socks - any") << QXmppTransferJob::SocksMethod << QXmppTransferJob::AnyMethod << true; QTest::newRow("socks - inband") << QXmppTransferJob::SocksMethod << QXmppTransferJob::InBandMethod << false; QTest::newRow("socks - socks") << QXmppTransferJob::SocksMethod << QXmppTransferJob::SocksMethod << true; } void tst_QXmppTransferManager::testSendFile() { QFETCH(QXmppTransferJob::Method, senderMethods); QFETCH(QXmppTransferJob::Method, receiverMethods); QFETCH(bool, works); const QString testDomain("localhost"); const QHostAddress testHost(QHostAddress::LocalHost); const quint16 testPort = 12345; QXmppLogger logger; //logger.setLoggingType(QXmppLogger::StdoutLogging); // prepare server TestPasswordChecker passwordChecker; passwordChecker.addCredentials("sender", "testpwd"); passwordChecker.addCredentials("receiver", "testpwd"); QXmppServer server; server.setDomain(testDomain); server.setLogger(&logger); server.setPasswordChecker(&passwordChecker); server.listenForClients(testHost, testPort); // prepare sender QXmppClient sender; QXmppTransferManager *senderManager = new QXmppTransferManager; senderManager->setSupportedMethods(senderMethods); sender.addExtension(senderManager); sender.setLogger(&logger); QEventLoop senderLoop; connect(&sender, SIGNAL(connected()), &senderLoop, SLOT(quit())); connect(&sender, SIGNAL(disconnected()), &senderLoop, SLOT(quit())); QXmppConfiguration config; config.setDomain(testDomain); config.setHost(testHost.toString()); config.setPort(testPort); config.setUser("sender"); config.setPassword("testpwd"); sender.connectToServer(config); senderLoop.exec(); QCOMPARE(sender.isConnected(), true); // prepare receiver QXmppClient receiver; QXmppTransferManager *receiverManager = new QXmppTransferManager; receiverManager->setSupportedMethods(receiverMethods); connect(receiverManager, SIGNAL(fileReceived(QXmppTransferJob*)), this, SLOT(acceptFile(QXmppTransferJob*))); receiver.addExtension(receiverManager); receiver.setLogger(&logger); QEventLoop receiverLoop; connect(&receiver, SIGNAL(connected()), &receiverLoop, SLOT(quit())); connect(&receiver, SIGNAL(disconnected()), &receiverLoop, SLOT(quit())); config.setUser("receiver"); config.setPassword("testpwd"); receiver.connectToServer(config); receiverLoop.exec(); QCOMPARE(receiver.isConnected(), true); // send file QEventLoop loop; QXmppTransferJob *senderJob = senderManager->sendFile("receiver@localhost/QXmpp", ":/test.svg"); QVERIFY(senderJob); QCOMPARE(senderJob->localFileUrl(), QUrl::fromLocalFile(":/test.svg")); connect(senderJob, SIGNAL(finished()), &loop, SLOT(quit())); loop.exec(); if (works) { QCOMPARE(senderJob->state(), QXmppTransferJob::FinishedState); QCOMPARE(senderJob->error(), QXmppTransferJob::NoError); // finish receiving file QVERIFY(receiverJob); connect(receiverJob, SIGNAL(finished()), &loop, SLOT(quit())); loop.exec(); QCOMPARE(receiverJob->state(), QXmppTransferJob::FinishedState); QCOMPARE(receiverJob->error(), QXmppTransferJob::NoError); // check received file QFile expectedFile(":/test.svg"); QVERIFY(expectedFile.open(QIODevice::ReadOnly)); const QByteArray expectedData = expectedFile.readAll(); QCOMPARE(receiverBuffer.data(), expectedData); } else { QCOMPARE(senderJob->state(), QXmppTransferJob::FinishedState); QCOMPARE(senderJob->error(), QXmppTransferJob::AbortError); QVERIFY(!receiverJob); QCOMPARE(receiverBuffer.data(), QByteArray()); } } QTEST_MAIN(tst_QXmppTransferManager) #include "tst_qxmpptransfermanager.moc" qxmpp-0.9.3/tests/qxmpptransfermanager/tst_qxmpptransfermanager.qrc000066400000000000000000000001341263006255200261440ustar00rootroot00000000000000 test.svg qxmpp-0.9.3/tests/qxmpputils/000077500000000000000000000000001263006255200162615ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmpputils/qxmpputils.pro000066400000000000000000000001541263006255200212310ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmpputils RESOURCES += tst_qxmpputils.qrc SOURCES += tst_qxmpputils.cpp qxmpp-0.9.3/tests/qxmpputils/test.bmp000066400000000000000000000002561263006255200177430ustar00rootroot00000000000000BM6(x  qxmpp-0.9.3/tests/qxmpputils/test.gif000066400000000000000000000000621263006255200177250ustar00rootroot00000000000000GIF87a, L$ʹ|N;qxmpp-0.9.3/tests/qxmpputils/test.jpg000066400000000000000000000005401263006255200177410ustar00rootroot00000000000000JFIFHHCreated with GIMP on a MacC  !"$"$C"656qt ?] image/svg+xml qxmpp-0.9.3/tests/qxmpputils/test.xpm000066400000000000000000000002341263006255200177650ustar00rootroot00000000000000/* XPM */ static char * test_xpm[] = { "6 6 3 1", " c #FF0000", ". c #00FF00", "+ c #0000FF", " ..++", " ..++", " ..++", " ..++", " ..++", " ..++"}; qxmpp-0.9.3/tests/qxmpputils/tst_qxmpputils.cpp000066400000000000000000000110741263006255200221100ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppUtils.h" #include "util.h" class tst_QXmppUtils : public QObject { Q_OBJECT private slots: void testCrc32(); void testHmac(); void testJid(); void testMime(); void testLibVersion(); void testTimezoneOffset(); }; void tst_QXmppUtils::testCrc32() { quint32 crc = QXmppUtils::generateCrc32(QByteArray()); QCOMPARE(crc, 0u); crc = QXmppUtils::generateCrc32(QByteArray("Hi There")); QCOMPARE(crc, 0xDB143BBEu); } void tst_QXmppUtils::testHmac() { QByteArray hmac = QXmppUtils::generateHmacMd5(QByteArray(16, '\x0b'), QByteArray("Hi There")); QCOMPARE(hmac, QByteArray::fromHex("9294727a3638bb1c13f48ef8158bfc9d")); hmac = QXmppUtils::generateHmacMd5(QByteArray("Jefe"), QByteArray("what do ya want for nothing?")); QCOMPARE(hmac, QByteArray::fromHex("750c783e6ab0b503eaa86e310a5db738")); hmac = QXmppUtils::generateHmacMd5(QByteArray(16, '\xaa'), QByteArray(50, '\xdd')); QCOMPARE(hmac, QByteArray::fromHex("56be34521d144c88dbb8c733f0e8b3f6")); } void tst_QXmppUtils::testJid() { QCOMPARE(QXmppUtils::jidToBareJid("foo@example.com/resource"), QLatin1String("foo@example.com")); QCOMPARE(QXmppUtils::jidToBareJid("foo@example.com"), QLatin1String("foo@example.com")); QCOMPARE(QXmppUtils::jidToBareJid("example.com"), QLatin1String("example.com")); QCOMPARE(QXmppUtils::jidToBareJid(QString()), QString()); QCOMPARE(QXmppUtils::jidToDomain("foo@example.com/resource"), QLatin1String("example.com")); QCOMPARE(QXmppUtils::jidToDomain("foo@example.com"), QLatin1String("example.com")); QCOMPARE(QXmppUtils::jidToDomain("example.com"), QLatin1String("example.com")); QCOMPARE(QXmppUtils::jidToDomain(QString()), QString()); QCOMPARE(QXmppUtils::jidToResource("foo@example.com/resource"), QLatin1String("resource")); QCOMPARE(QXmppUtils::jidToResource("foo@example.com"), QString()); QCOMPARE(QXmppUtils::jidToResource("example.com"), QString()); QCOMPARE(QXmppUtils::jidToResource(QString()), QString()); QCOMPARE(QXmppUtils::jidToUser("foo@example.com/resource"), QLatin1String("foo")); QCOMPARE(QXmppUtils::jidToUser("foo@example.com"), QLatin1String("foo")); QCOMPARE(QXmppUtils::jidToUser("example.com"), QString()); QCOMPARE(QXmppUtils::jidToUser(QString()), QString()); } // FIXME: how should we test MIME detection without expose getImageType? #if 0 QString getImageType(const QByteArray &contents); static void testMimeType(const QString &fileName, const QString fileType) { // load file from resources QFile file(":/" + fileName); QCOMPARE(file.open(QIODevice::ReadOnly), true); QCOMPARE(getImageType(file.readAll()), fileType); file.close(); } void tst_QXmppUtils::testMime() { testMimeType("test.bmp", "image/bmp"); testMimeType("test.gif", "image/gif"); testMimeType("test.jpg", "image/jpeg"); testMimeType("test.mng", "video/x-mng"); testMimeType("test.png", "image/png"); testMimeType("test.svg", "image/svg+xml"); testMimeType("test.xpm", "image/x-xpm"); } #else void tst_QXmppUtils::testMime() { } #endif void tst_QXmppUtils::testLibVersion() { QCOMPARE(QXmppVersion(), QString("0.9.3")); } void tst_QXmppUtils::testTimezoneOffset() { // parsing QCOMPARE(QXmppUtils::timezoneOffsetFromString("Z"), 0); QCOMPARE(QXmppUtils::timezoneOffsetFromString("+00:00"), 0); QCOMPARE(QXmppUtils::timezoneOffsetFromString("-00:00"), 0); QCOMPARE(QXmppUtils::timezoneOffsetFromString("+01:30"), 5400); QCOMPARE(QXmppUtils::timezoneOffsetFromString("-01:30"), -5400); // serialization QCOMPARE(QXmppUtils::timezoneOffsetToString(0), QLatin1String("Z")); QCOMPARE(QXmppUtils::timezoneOffsetToString(5400), QLatin1String("+01:30")); QCOMPARE(QXmppUtils::timezoneOffsetToString(-5400), QLatin1String("-01:30")); } QTEST_MAIN(tst_QXmppUtils) #include "tst_qxmpputils.moc" qxmpp-0.9.3/tests/qxmpputils/tst_qxmpputils.qrc000066400000000000000000000003701263006255200221100ustar00rootroot00000000000000 test.bmp test.gif test.jpg test.mng test.png test.svg test.xpm qxmpp-0.9.3/tests/qxmppvcardiq/000077500000000000000000000000001263006255200165525ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppvcardiq/qxmppvcardiq.pro000066400000000000000000000001201263006255200220040ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppvcardiq SOURCES += tst_qxmppvcardiq.cpp qxmpp-0.9.3/tests/qxmppvcardiq/tst_qxmppvcardiq.cpp000066400000000000000000000247731263006255200227040ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Author: * Jeremy Lainé * * Source: * https://github.com/qxmpp-project/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 "QXmppVCardIq.h" #include "util.h" class tst_QXmppVCardIq : public QObject { Q_OBJECT private slots: void testAddress_data(); void testAddress(); void testEmail_data(); void testEmail(); void testPhone_data(); void testPhone(); void testVCard(); }; void tst_QXmppVCardIq::testAddress_data() { QTest::addColumn("xml"); QTest::addColumn("type"); QTest::addColumn("country"); QTest::addColumn("locality"); QTest::addColumn("postcode"); QTest::addColumn("region"); QTest::addColumn("street"); QTest::addColumn("equalsEmpty"); QTest::newRow("none") << QByteArray("") << int(QXmppVCardAddress::None) << "" << "" << "" << "" << "" << true; QTest::newRow("HOME") << QByteArray("") << int(QXmppVCardAddress::Home) << "" << "" << "" << "" << "" << false; QTest::newRow("WORK") << QByteArray("") << int(QXmppVCardAddress::Work) << "" << "" << "" << "" << "" << false; QTest::newRow("POSTAL") << QByteArray("") << int(QXmppVCardAddress::Postal) << "" << "" << "" << "" << "" << false; QTest::newRow("PREF") << QByteArray("") << int(QXmppVCardAddress::Preferred) << "" << "" << "" << "" << "" << false; QTest::newRow("country") << QByteArray("France") << int(QXmppVCardAddress::None) << "France" << "" << "" << "" << "" << false; QTest::newRow("locality") << QByteArray("Paris") << int(QXmppVCardAddress::None) << "" << "Paris" << "" << "" << "" << false; QTest::newRow("postcode") << QByteArray("75008") << int(QXmppVCardAddress::None) << "" << "" << "75008" << "" << "" << false; QTest::newRow("region") << QByteArray("Ile de France") << int(QXmppVCardAddress::None) << "" << "" << "" << "Ile de France" << "" << false; QTest::newRow("street") << QByteArray("55 rue du faubourg Saint-Honoré") << int(QXmppVCardAddress::None) << "" << "" << "" << "" << QString::fromUtf8("55 rue du faubourg Saint-Honoré") << false; } void tst_QXmppVCardIq::testAddress() { QFETCH(QByteArray, xml); QFETCH(int, type); QFETCH(QString, country); QFETCH(QString, locality); QFETCH(QString, postcode); QFETCH(QString, region); QFETCH(QString, street); QFETCH(bool, equalsEmpty); QXmppVCardAddress address; parsePacket(address, xml); QCOMPARE(int(address.type()), type); QCOMPARE(address.country(), country); QCOMPARE(address.locality(), locality); QCOMPARE(address.postcode(), postcode); QCOMPARE(address.region(), region); QCOMPARE(address.street(), street); serializePacket(address, xml); QXmppVCardAddress addressCopy = address; QVERIFY2(addressCopy == address, "QXmppVCardAddres::operator==() fails"); QVERIFY2(!(addressCopy != address), "QXmppVCardAddres::operator!=() fails"); QXmppVCardAddress emptyAddress; QCOMPARE(emptyAddress == address, equalsEmpty); QCOMPARE(emptyAddress != address, !equalsEmpty); } void tst_QXmppVCardIq::testEmail_data() { QTest::addColumn("xml"); QTest::addColumn("type"); QTest::newRow("none") << QByteArray("foo.bar@example.com") << int(QXmppVCardEmail::None); QTest::newRow("HOME") << QByteArray("foo.bar@example.com") << int(QXmppVCardEmail::Home); QTest::newRow("WORK") << QByteArray("foo.bar@example.com") << int(QXmppVCardEmail::Work); QTest::newRow("INTERNET") << QByteArray("foo.bar@example.com") << int(QXmppVCardEmail::Internet); QTest::newRow("X400") << QByteArray("foo.bar@example.com") << int(QXmppVCardEmail::X400); QTest::newRow("PREF") << QByteArray("foo.bar@example.com") << int(QXmppVCardEmail::Preferred); QTest::newRow("all") << QByteArray("foo.bar@example.com") << int(QXmppVCardEmail::Home | QXmppVCardEmail::Work | QXmppVCardEmail::Internet | QXmppVCardEmail::Preferred | QXmppVCardEmail::X400); } void tst_QXmppVCardIq::testEmail() { QFETCH(QByteArray, xml); QFETCH(int, type); QXmppVCardEmail email; parsePacket(email, xml); QCOMPARE(email.address(), QLatin1String("foo.bar@example.com")); QCOMPARE(int(email.type()), type); serializePacket(email, xml); } void tst_QXmppVCardIq::testPhone_data() { QTest::addColumn("xml"); QTest::addColumn("type"); QTest::newRow("none") << QByteArray("12345") << int(QXmppVCardPhone::None); QTest::newRow("HOME") << QByteArray("12345") << int(QXmppVCardPhone::Home); QTest::newRow("WORK") << QByteArray("12345") << int(QXmppVCardPhone::Work); QTest::newRow("VOICE") << QByteArray("12345") << int(QXmppVCardPhone::Voice); QTest::newRow("FAX") << QByteArray("12345") << int(QXmppVCardPhone::Fax); QTest::newRow("PAGER") << QByteArray("12345") << int(QXmppVCardPhone::Pager); QTest::newRow("MSG") << QByteArray("12345") << int(QXmppVCardPhone::Messaging); QTest::newRow("CELL") << QByteArray("12345") << int(QXmppVCardPhone::Cell); QTest::newRow("VIDEO") << QByteArray("") << int(QXmppVCardPhone::Video); QTest::newRow("BBS") << QByteArray("12345") << int(QXmppVCardPhone::BBS); QTest::newRow("MODEM") << QByteArray("12345") << int(QXmppVCardPhone::Modem); QTest::newRow("IDSN") << QByteArray("12345") << int(QXmppVCardPhone::ISDN); QTest::newRow("PCS") << QByteArray("12345") << int(QXmppVCardPhone::PCS); QTest::newRow("PREF") << QByteArray("12345") << int(QXmppVCardPhone::Preferred); } void tst_QXmppVCardIq::testPhone() { QFETCH(QByteArray, xml); QFETCH(int, type); QXmppVCardPhone phone; parsePacket(phone, xml); QCOMPARE(phone.number(), QLatin1String("12345")); QCOMPARE(int(phone.type()), type); serializePacket(phone, xml); } void tst_QXmppVCardIq::testVCard() { const QByteArray xml( "" "" "France" "1983-09-14" "I like XMPP." "foo.bar@example.com" "Foo Bar!" "FooBar" "FooWizBaz" "12345" "67890" "" "image/png" "" "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAAXNSR0IArs4c6QAAAAlwSFlzAAA" "UIgAAFCIBjw1HyAAAAAd0SU1FB9oIHQInNvuJovgAAAAiSURBVAjXY2TQ+s/AwMDAwPD/GiMDlP" "WfgYGBiQEHGJwSAK2BBQ1f3uvpAAAAAElFTkSuQmCC" "" "" "https://github.com/qxmpp-project/qxmpp/" "" "QXmpp foundation" "Main QXmpp dev unit" "" "Executive Director" "Patron Saint" "" ""); QXmppVCardIq vcard; parsePacket(vcard, xml); QCOMPARE(vcard.addresses().size(), 1); QCOMPARE(vcard.addresses()[0].country(), QLatin1String("France")); QCOMPARE(int(vcard.addresses()[0].type()), int(QXmppVCardEmail::None)); QCOMPARE(vcard.birthday(), QDate(1983, 9, 14)); QCOMPARE(vcard.description(), QLatin1String("I like XMPP.")); QCOMPARE(vcard.email(), QLatin1String("foo.bar@example.com")); QCOMPARE(vcard.emails().size(), 1); QCOMPARE(vcard.emails()[0].address(), QLatin1String("foo.bar@example.com")); QCOMPARE(int(vcard.emails()[0].type()), int(QXmppVCardEmail::Internet)); QCOMPARE(vcard.nickName(), QLatin1String("FooBar")); QCOMPARE(vcard.fullName(), QLatin1String("Foo Bar!")); QCOMPARE(vcard.firstName(), QLatin1String("Foo")); QCOMPARE(vcard.middleName(), QLatin1String("Baz")); QCOMPARE(vcard.lastName(), QLatin1String("Wiz")); QCOMPARE(vcard.phones().size(), 2); QCOMPARE(vcard.phones()[0].number(), QLatin1String("12345")); QCOMPARE(int(vcard.phones()[0].type()), int(QXmppVCardEmail::Home)); QCOMPARE(vcard.phones()[1].number(), QLatin1String("67890")); QCOMPARE(int(vcard.phones()[1].type()), int(QXmppVCardEmail::Work)); QCOMPARE(vcard.photo(), QByteArray::fromBase64( "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAAXNSR0IArs4c6QAAAAlwSFlzAAA" "UIgAAFCIBjw1HyAAAAAd0SU1FB9oIHQInNvuJovgAAAAiSURBVAjXY2TQ+s/AwMDAwPD/GiMDlP" "WfgYGBiQEHGJwSAK2BBQ1f3uvpAAAAAElFTkSuQmCC")); QCOMPARE(vcard.photoType(), QLatin1String("image/png")); QCOMPARE(vcard.url(), QLatin1String("https://github.com/qxmpp-project/qxmpp/")); const QXmppVCardOrganization &orgInfo = vcard.organization(); QCOMPARE(orgInfo.organization(), QLatin1String("QXmpp foundation")); QCOMPARE(orgInfo.unit(), QLatin1String("Main QXmpp dev unit")); QCOMPARE(orgInfo.title(), QLatin1String("Executive Director")); QCOMPARE(orgInfo.role(), QLatin1String("Patron Saint")); serializePacket(vcard, xml); } QTEST_MAIN(tst_QXmppVCardIq) #include "tst_qxmppvcardiq.moc" qxmpp-0.9.3/tests/qxmppversioniq/000077500000000000000000000000001263006255200171405ustar00rootroot00000000000000qxmpp-0.9.3/tests/qxmppversioniq/qxmppversioniq.pro000066400000000000000000000001241263006255200227640ustar00rootroot00000000000000include(../tests.pri) TARGET = tst_qxmppversioniq SOURCES += tst_qxmppversioniq.cpp qxmpp-0.9.3/tests/qxmppversioniq/tst_qxmppversioniq.cpp000066400000000000000000000047131263006255200236500ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppVersionIq.h" #include "util.h" class tst_QXmppVersionIq : public QObject { Q_OBJECT private slots: void testVersionGet(); void testVersionResult(); }; void tst_QXmppVersionIq::testVersionGet() { const QByteArray xmlGet( "" ""); QXmppVersionIq verIqGet; parsePacket(verIqGet, xmlGet); QCOMPARE(verIqGet.id(), QLatin1String("version_1")); QCOMPARE(verIqGet.to(), QLatin1String("juliet@capulet.com/balcony")); QCOMPARE(verIqGet.from(), QLatin1String("romeo@montague.net/orchard")); QCOMPARE(verIqGet.type(), QXmppIq::Get); serializePacket(verIqGet, xmlGet); } void tst_QXmppVersionIq::testVersionResult() { const QByteArray xmlResult( "" "" "qxmpp" "Windows-XP" "0.2.0" ""); QXmppVersionIq verIqResult; parsePacket(verIqResult, xmlResult); QCOMPARE(verIqResult.id(), QLatin1String("version_1")); QCOMPARE(verIqResult.to(), QLatin1String("romeo@montague.net/orchard")); QCOMPARE(verIqResult.from(), QLatin1String("juliet@capulet.com/balcony")); QCOMPARE(verIqResult.type(), QXmppIq::Result); QCOMPARE(verIqResult.name(), QString("qxmpp")); QCOMPARE(verIqResult.version(), QString("0.2.0")); QCOMPARE(verIqResult.os(), QString("Windows-XP")); serializePacket(verIqResult, xmlResult); } QTEST_MAIN(tst_QXmppVersionIq) #include "tst_qxmppversioniq.moc" qxmpp-0.9.3/tests/tests.pri000066400000000000000000000004261263006255200157130ustar00rootroot00000000000000include(../qxmpp.pri) QT -= gui QT += testlib CONFIG -= app_bundle CONFIG += testcase QMAKE_LIBDIR += ../../src QMAKE_RPATHDIR += $$OUT_PWD/../../src INCLUDEPATH += $$PWD $$QXMPP_INCLUDEPATH LIBS += $$QXMPP_LIBS # do not install testcases target.CONFIG += no_default_install qxmpp-0.9.3/tests/tests.pro000066400000000000000000000013701263006255200157200ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS = \ qxmpparchiveiq \ qxmppbindiq \ qxmppcallmanager \ qxmppdataform \ qxmppdiscoveryiq \ qxmppentitytimeiq \ qxmppiceconnection \ qxmppiq \ qxmppjingleiq \ qxmppmessage \ qxmppnonsaslauthiq \ qxmpppresence \ qxmpppubsubiq \ qxmppregisteriq \ qxmppresultset \ qxmpprosteriq \ qxmpprpciq \ qxmpprtcppacket \ qxmpprtppacket \ qxmppserver \ qxmppsessioniq \ qxmppsocks \ qxmppstanza \ qxmppstreamfeatures \ qxmppstunmessage \ qxmpptransfermanager \ qxmpputils \ qxmppvcardiq \ qxmppversioniq !isEmpty(QXMPP_AUTOTEST_INTERNAL) { SUBDIRS += qxmppcodec SUBDIRS += qxmppsasl SUBDIRS += qxmppstreaminitiationiq } qxmpp-0.9.3/tests/travis/000077500000000000000000000000001263006255200153435ustar00rootroot00000000000000qxmpp-0.9.3/tests/travis/build-and-test000077500000000000000000000011031263006255200201000ustar00rootroot00000000000000#!/bin/sh set -e QMAKE_ARGS="" if [ -n "$CC" ]; then QMAKE_ARGS="$QMAKE_ARGS QMAKE_CC=$CC" fi if [ -n "$CXX" ]; then QMAKE_ARGS="$QMAKE_ARGS QMAKE_CXX=$CXX" fi case "$CONFIG" in full*) QMAKE_ARGS="$QMAKE_ARGS QXMPP_USE_DOXYGEN=1 QXMPP_USE_OPUS=1 QXMPP_USE_SPEEX=1 QXMPP_USE_THEORA=1 QXMPP_USE_VPX=1" ;; esac case "$CONFIG" in *debug*) QMAKE_ARGS="$QMAKE_ARGS CONFIG+=debug" ;; esac case "$CONFIG" in *static*) QMAKE_ARGS="$QMAKE_ARGS QXMPP_LIBRARY_TYPE=staticlib" ;; esac # compile qmake $QMAKE_ARGS make VERBOSE=1 # run tests make check qxmpp-0.9.3/tests/travis/install-build-depends000077500000000000000000000005271263006255200214600ustar00rootroot00000000000000#!/bin/sh set -e sudo add-apt-repository -y ppa:ubuntu-sdk-team/ppa sudo apt-get update -qq if [ "$QT_SELECT" = "qt4" ]; then sudo apt-get install -qq libqt4-dev else sudo apt-get install -qq qtbase5-dev fi case "$CONFIG" in full*) sudo apt-get install -qq doxygen libopus-dev libspeex-dev libtheora-dev libvpx-dev ;; esac qxmpp-0.9.3/tests/util.h000066400000000000000000000042201263006255200151570ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 The QXmpp developers * * Authors: * Jeremy Lainé * Manjeet Dahiya * * Source: * https://github.com/qxmpp-project/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 "QXmppPasswordChecker.h" template static void parsePacket(T &packet, const QByteArray &xml) { //qDebug() << "parsing" << xml; QDomDocument doc; QCOMPARE(doc.setContent(xml, true), true); QDomElement element = doc.documentElement(); packet.parse(element); } template static void serializePacket(T &packet, const QByteArray &xml) { QBuffer buffer; buffer.open(QIODevice::ReadWrite); QXmlStreamWriter writer(&buffer); packet.toXml(&writer); qDebug() << "expect " << xml; qDebug() << "writing" << buffer.data(); QCOMPARE(buffer.data(), xml); } class TestPasswordChecker : public QXmppPasswordChecker { public: void addCredentials(const QString &user, const QString &password) { m_credentials.insert(user, password); }; /// Retrieves the password for the given username. QXmppPasswordReply::Error getPassword(const QXmppPasswordRequest &request, QString &password) { if (m_credentials.contains(request.username())) { password = m_credentials.value(request.username()); return QXmppPasswordReply::NoError; } else { return QXmppPasswordReply::AuthorizationError; } }; /// Returns whether getPassword() is enabled. bool hasGetPassword() const { return true; }; private: QMap m_credentials; };